【经典面试题】请使用C语言编程实现对IPV4地址的合法性判断

news2024/9/8 23:14:59

C语言编程实现对IPV4地址的合法性判断

有了解过我的朋友,可能有点印象,我在N年前的博客中,就写了这个主题,当时确实是工作中遇到了这个问题。本想着等工作搞完之后,就把这个问题的解决代码补上,结果一鸽,就是好几年,真是惭愧。现在把这部分代码公开,欢迎大家来下载测试。

文章目录

  • 1 写在前面
  • 2 需求分析
  • 3 简单版本
  • 4 进阶一下
  • 5 高阶版本
  • 6 完整测试用例

1 写在前面

有了解过我的朋友,可能有点印象,我在N年前的博客中,就写了这个主题,当时确实是工作中遇到了这个问题。本想着等工作搞完之后,就把这个问题的解决代码补上,结果一鸽,就是好几年,真是惭愧。现在把这部分代码公开,欢迎大家来下载测试。

如果你发现代码有问题,欢迎与我私信联系。

2 需求分析

其实,本专题的需求很简单,就是输入一段字符串,判断它是不是合法的IPv4地址。仅仅从功能上看,似乎很简单,但是真正要做到很完美,也是需要下点功夫的。不信,你看看下文的拆解。

IPV4 的图像结果

3 简单版本

我们先上一个简单版本,直接看代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int is_valid_ipv4(const char *ip_address) 
{
    int num, dots = 0;
    char *ptr;

    if (ip_address == NULL) {
        return 0;
    }

    ptr = strtok((char *)ip_address, ".");
    if (ptr == NULL) {
        return 0;
    }

    while (ptr) {
        if (!isdigit(*ptr)) {
            return 0;
        }

        num = atoi(ptr);
        if (num < 0 || num > 255) {
            return 0;
        }

        ptr = strtok(NULL, ".");
        if (ptr != NULL) {
            dots++;
        }
    }

    if (dots != 3) {
        return 0;
    }

    return 1;
}

int check_is_valid_ipv4(const char *ip)
{
    int ret = 0;
    
    ret = is_valid_ipv4(ip); 

    return ret; 
}

int main(int argc, const char *argv[])
{
    const char *ip = argv[1];

    printf("check %s\n", ip);
    printf("ret %d\n", check_is_valid_ipv4(ip));
}

编译运行一下,输入一个常见的ipv4地址是没有问题,比如 “192.168.0.1”;同时,非法的字符输入也是会报错的。

~/ipv4]$gcc -o test ipv4.c 
~/ipv4]$./test 192.168.0.1
check 192.168.0.1
ret 1
~/ipv4]$./test 
check 192.168.w.2
ret 0

但是,如果我加一个限制:如何判断一个IPV4地址是一个合法的 主机地址 呢?

比如这个:“238.171.84.41”,它的判断还是合法的哦,实际上这不是合法的 主机地址

~/ipv4]$./test 238.171.84.41
check 238.171.84.41
ret 1

另外一个,上面的代码还检测不到,诸如此类的输入:“0192.168.1.1”

~/ipv4]$./test 0192.168.1.1
check 0192.168.1.1
ret 1

所以,我们需要优化一下。

4 进阶一下

正如上面的分析,我们需要对代码进行优化:

首先得判断按照 “.” 分割后的数字段,不能以 “0” 字符开头。

    while (ptr) {
        if (!isdigit(*ptr)) {
            return 0;
        }

        if (*ptr == '0') { //check start with '0'
            return 0;
        }

        num = atoi(ptr);
        if (num < 0 || num > 255) {
            return 0;
        }

        ptr = strtok(NULL, ".");
        if (ptr != NULL) {
            dots++;
        }
    }

~/ipv4]$./test 0192.168.1.1
check 0192.168.1.1
ret 0

根据IPv4地址的分类:

  • A类:(1.0.0.1-126.255.255.254)(默认子网掩码:255.0.0.0或0xFF000000)第一个字节为网络号,后三个字节为主机号,表示为网络–主机–主机–主机。该类IP地址的最前面为“0”,所以地址的网络号取值于1~126之间。共有16777214个主机地址,一般用于大型网络。

  • B类:(128.1.0.1-191.254.255.254)(默认子网掩码:255.255.0.0或0xFFFF0000)前两个字节为网络号,后两个字节为主机号。该类IP地址的最前面为“10”,所以地址的网络号取值于128~191之间。共有65534个主机地址,一般用于中等规模网络。

  • C类:(192.0.1.1-223.255.254.254)(子网掩码:255.255.255.0或0xFFFFFF00)前三个字节为网络号,最后一个字节为主机号。该类IP地址的最前面为“110”,所以地址的网络号取值于192~223之间。共有254个主机地址,一般用于小型网络。

  • D类:是多播地址。(224.0.0.1-239.255.255.254) 该类IP地址的前面4位为“1110”,所以网络号取值于224~239之间;后面28位为组播地址ID。这是一个专门保留的地址。它并不指向特定的网络,目前这一类地址被用在多点广播(Multicasting)中。多点广播地址用来一次寻址一组计算机,它标识共享同一协议的一组计算机。

  • E类:是保留地址,为将来使用保留。(240.0.0.0—255.255.255.254) 该类IP地址的最前面为“1111”,所以网络号取值于240~255之间。

可知,如果要符合一个正常的IPv4主机地址,只能是A、B、C类,而不能是D、E类。

所以在判断时,我们应该增加IPv4地址的类别判断。

在上面的判断返回前,增加一个判断:

	if (atoi(ip_address) >= 1 && atoi(ip_address) <= 126) {
        printf("This is a Class A IP address.\n");
        return 1;
    } else if (atoi(ip_address) >= 128 && atoi(ip_address) <= 191) {
        printf("This is a Class B IP address.\n");
        return 1;
    } else if (atoi(ip_address) >= 192 && atoi(ip_address) <= 223) {
        printf("This is a Class C IP address.\n");
        return 1;
    } else {
        printf("This is not a Class A, B, or C IP address.\n");
        return 0;
    }

完整的代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int is_valid_ipv4(const char *ip_address) 
{
    int num, dots = 0;
    char *ptr;

    if (ip_address == NULL) {
        return 0;
    }

    ptr = strtok((char *)ip_address, ".");
    if (ptr == NULL) {
        return 0;
    }

    while (ptr) {
        if (!isdigit(*ptr)) {
            return 0;
        }

        if (*ptr == '0') { //check start '0'
            return 0;
        }

        num = atoi(ptr);
        if (num < 0 || num > 255) {
            return 0;
        }

        ptr = strtok(NULL, ".");
        if (ptr != NULL) {
            dots++;
        }
    }

    if (dots != 3) {
        return 0;
    }

    if (atoi(ip_address) >= 1 && atoi(ip_address) <= 126) {
        printf("This is a Class A IP address.\n");
        return 1;
    } else if (atoi(ip_address) >= 128 && atoi(ip_address) <= 191) {
        printf("This is a Class B IP address.\n");
        return 1;
    } else if (atoi(ip_address) >= 192 && atoi(ip_address) <= 223) {
        printf("This is a Class C IP address.\n");
        return 1;
    } else {
        printf("This is not a Class A, B, or C IP address.\n");
        return 0;
    }

    return 1;
}

int check_is_valid_ipv4(const char *ip)
{
    int ret = 0;
    
    ret = is_valid_ipv4(ip); 

    return ret; 
}

int main(int argc, const char *argv[])
{
    const char *ip = argv[1];

    printf("check %s\n", ip);
    printf("ret %d\n", check_is_valid_ipv4(ip));
}

这个时候,我们再试一下之前的非A/B/C类的IPv4地址:

~/ipv4]$./test 238.171.84.41
check 238.171.84.41
This is not a Class A, B, or C IP address.
ret 0

~/ipv4]$./test 192.168.2.3
check 192.168.2.3
This is a Class C IP address.
ret 1

至此,基本得到了比较完美的判断,但有没有漏洞呢?留给读者自己去思考吧。

5 高阶版本

有经验的程序一定会发现,上面的各个判断真的号麻烦啊!

每个case都需要这样去比较判断,那得多费劲啊!

有没有更加清爽一点的高阶方法啊?

答案当然是有的,这个时候你就需要了解一下:正则表达式 了。

很多主流的编程语言都有标准库来支持正则表达式,那么C语言里面有没有呢?

其实C语言里面也是可以用正则表达式的,这个先留个悬念,且听下回分解。

欢迎打击提前预习下:正则表达式语言 - 快速参考 | Microsoft Learn

6 完整测试用例

本小节给大家补充一下各种测试用例,希望对大家测试代码有帮助:

合法的测试输入
192.168.0.1
10.0.0.1
172.16.0.1
255.255.255.255

非法的测试输入
256.0.0.1
192.168.0.0.1
192.168.0
192.168.0.1.2

非法的测试输入
256.0.0.1
192.168.0.0.1
192.168.0
192.168.0.1.2
300.300.300.300
1.2.3
1.2.3.4.5
1.2.3.4.
.1.2.3.4
1..2.3.4

测试用例是不断丰富的,欢迎大家来补充。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/489245.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MATLAB实现工业PCB电路板缺陷识别和检测

PCB&#xff08;PrintedCircuitBoard印刷电路板&#xff09;是电子产品中众多电子元器件的承载体&#xff0c;它为各电子元器件的秩序连接提供了可能&#xff0c;PCB已成为现代电子产品的核心部分。随着现代电子工业迅猛发展&#xff0c;电子技术不断革新&#xff0c;PCB密集度…

K8S常见异常事件与解决方案

集群相关 Coredns容器或local-dns容器重启 集群中的coredns组件发生重启(重新创建)&#xff0c;一般是由于coredns组件压力较大导致oom&#xff0c;请检查业务是否异常&#xff0c;是否存在应用容器无法解析域名的异常。 如果是local-dns重启&#xff0c;说明local-dns的性能…

fastai2 实现SSD

https://github.com/search?qfastaissd 有几个值得参考的代码&#xff0c;好好学习。 GitHub - Samjoel3101/SSD-Object-Detection: I am working on a SSD Object Detector using fastai and pytorch fastai2实现的SSD&#xff0c;终于找到了code。https://github.com/sidrav…

等保定级怎么做

Q25:现在还没做等保还来得及吗?有什么影响? 答:来得及。种一棵树,最好的时间是十年前,其次是现在。可先根据定级备案要求和流程,先向公安递交定级备案文件,测评与整改预算提上日程,在经费未落实前,可以先进行系统定级、差距分析、整改计划制订等工作。 根据《等保工…

LVGL移植——stm32f4

LVGL移植说明 移植LVGL版本&#xff1a;8.3.6 主控&#xff1a;STM32F407ZGT6 github链接&#xff1a;https://github.com/lvgl/lvgl.git 文章目录 LVGL移植说明STM32移植LVGL①需要的依赖文件②移植显示驱动文件③将文件加入工程当中④配置心跳④修改栈堆的空间⑤编译链接 STM…

02-权限提升-Win溢出漏洞及ATSCPS提权

权限提升-Win溢出漏洞及AT&SC&PS提权 思维导图 明确权限提升基础知识&#xff1a;权限划分 明确权限提升环境问题&#xff1a;web及本地 web提权&#xff1a;已有网站权限&#xff08;可以操作网站内容&#xff0c;但无法操作服务器&#xff09;&#xff0c;想要获得…

【软考中级】2022下半年软件设计师综合知识真题与答案

1、以下关于R1SC(精简指令集计算机)特点的叙述中&#xff0c;错误的是()。 A.对存储器操作进行限制&#xff0c;使控制简单化 B.指令种类多&#xff0c;指令功能强 C.设置大量通用寄存器 D.选取使用频率较高的一些指令&#xff0c;提高执行速度 参考答案&#xff1a;B 2、…

Qt6之KDE框架

25年来&#xff0c;KDE社区一直在使用Qt开发各种自由软件产品。其中包括Plasma桌面环境&#xff0c;像Krita和Kdenlive这样的创意工具&#xff0c;像GCompris这样的教育应用程序&#xff0c;像Kontact这样的群件套件以及无数其他应用程序&#xff0c;实用程序和小部件。 Qt以其…

Shell+VCS学习3---VCS命令

1 VCS介绍 VCS的功能可以大致分为两个大类&#xff1a;编译和仿真。 VCS编译的过程&#xff0c;就是经过一系列的操作&#xff0c;将verilog代码转换为可执行文件&#xff08;.svim&#xff09;&#xff0c;接下来就是用dve进行仿真过程生成.vpd波形文件。 VCS是编译型verilo…

C++---树形DP---树的最长路径(每日一道算法2023.5.4)

注意事项&#xff1a; 本题为"树与图的DFS深度优先遍历—树的重心"的近似题&#xff0c;同时涉及到 单链表模拟邻接表存储图 的操作&#xff0c;建议先理解那篇文章。 题目&#xff1a; 给定一棵树&#xff0c;树中包含 n 个结点&#xff08;编号1~n&#xff09;和 …

JavaScript:栈和对列

文章目录 栈和对列Js 有栈与队列吗20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09;思路 1047. 删除字符串中的所有相邻重复项 - 力扣&#xff08;LeetCode&#xff09;思路代码分析array.join() 操作打印const s of str 操作遍历 150. 逆波兰表达式求值 - 力扣&#xf…

(1)QT基础铺垫

目录 1.Qt特性 2. 新建项目 3. 工作目录与构建目录 4. 工作目录 4.1 .pro 项目配置文件 4.2 dialog.h 4.3 dialog.cpp 4.4 main.cpp 5. 帮助文档 6. 调试信息 1.Qt特性 Qt经常被当作是一个基于c语言的gui开发框架&#xff0c;但是这并不是qt的全部&#xff0c;除了开…

助力工业物联网,工业大数据之ODS层构建:申明分区代码及测试【十】

文章目录 知识点13&#xff1a;ODS层构建&#xff1a;申明分区代码及测试知识点14&#xff1a;ODS层与DWD层区别知识点15&#xff1a;DWD层构建&#xff1a;需求分析知识点16&#xff1a;DWD层构建&#xff1a;建库实现测试知识点17&#xff1a;DWD层构建&#xff1a;建表实现测…

Packet Tracer – 研究 VLAN 实施

Packet Tracer – 研究 VLAN 实施 地址分配表 设备 接口 IP 地址 子网掩码 默认网关 S1 VLAN 99 172.17.99.31 255.255.255.0 不适用 S2 VLAN 99 172.17.99.32 255.255.255.0 不适用 S3 VLAN 99 172.17.99.33 255.255.255.0 不适用 PC1 NIC 172.17.10.2…

Linux部署Gitlab/上传项目

一、提前准备 1.1安装依赖工具 yum install -y curl policycoreutils-python openssh-serversystemctl start sshd systemctl enable sshd 1.2安装Postfix邮件服务器 #安装 postfix yum install -y postfix#启动 postfix 并设置为开机启动 systemctl enable postfix systemctl …

HashCode与String大家庭

当金钱站起来说话时&#xff0c;所有的真理都保持了沉默&#xff1b;金钱一旦作响&#xff0c;坏话随之戛然而止。 Hashcode的作用 java的集合有两类&#xff0c;一类是List&#xff0c;还有一类是Set 前者有序可重复&#xff0c;后者无序不重复。当我们在set中插入的时候怎…

Vue传参${id}变成$%7Bid%7D

发生缘由 外卖项目在Linux服务器上面运行发送请求乱码 运行环境 电脑系统&#xff1a;win10jdk版本&#xff1a;jdk-8SpringBoot版本&#xff1a;v2.4.5MP版本&#xff1a;3.4.2Vue版本&#xff1a;Vue.js v2.6.12Linux版本&#xff1a;Centos7 报错信息 // 修改页面反查详…

MES系统中的BOM为何如此重要?先进的BOM体系怎么构建?

其实不管有没有数字化&#xff0c;BOM都是制造企业的灵魂纽带&#xff0c;对于产品繁多、流程冗长的工业企业来说&#xff0c;如果BOM管理不规范&#xff0c;必然对生产效率和产品质量带来巨大的隐患&#xff0c;因此在工业企业的数字化转型之路中&#xff0c;建立科学规范的BO…

Blender 建模练习-锁链

目录 1.1.1 贝塞尔圆1.2 阵列修改器1.3 阵列修改器 物体偏移1.4 添加贝塞尔曲线1.5 曲线修改器 1. 本次练习主要使用到阵列修改器、贝塞尔曲线、空物体 1.1 贝塞尔圆 把贝塞尔圆进行缩放&#xff0c;然后在物体数据属性|几何数据|倒角|设置倒角深度为0.05 1.2 阵列修改器 …

【数据结构】二叉树(详细)

二叉树 1.树1.1定义1.2基本术语1.3树形结构和线性结构1.4树的存储结构1.4.1双亲表示法1.4.2孩子兄弟表示法 2.二叉树2.1定义2.2特殊二叉树2.3性质2.4存储结构2.4.1顺序存储2.4.2链式存储结构 3.二叉树的基本操作3.1前序遍历&#xff08;先序遍历&#xff09;3.2中序遍历3.3后序…