0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

嵌入式物联网开发 来源: 嵌入式物联网开发 作者: 嵌入式物联网开发 2023-05-16 15:23 次阅读

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

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

@[toc]
# 1 写在前面

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

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

# 2 需求分析

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

![IPV4 的图像结果](https://img-blog.csdnimg.cn/img_convert/994e3109304e34a6bbd59db8247d37c6.jpeg)

# 3 简单版本

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

```c
#include
#include
#include
#include

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 %sn", ip);
printf("ret %dn", check_is_valid_ipv4(ip));
}
```

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

```c
~/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”,它的判断还是合法的哦,实际上这不是合法的 **主机地址** 。

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

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

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

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

# 4 进阶一下

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

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

```c
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地址的类别判断。

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

```c
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;
}
```

完整的代码如下:

```c
#include
#include
#include
#include

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 %sn", ip);
printf("ret %dn", check_is_valid_ipv4(ip));
}
```

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

```c
~/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](https://learn.microsoft.com/zh-cn/dotnet/standard/base-types/regular-expression-language-quick-reference)

# 6 完整测试用例

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

```c
合法的测试输入
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
```

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

审核编辑黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7533

    浏览量

    128814
  • IPv4
    +关注

    关注

    0

    文章

    131

    浏览量

    19689
收藏 人收藏

    评论

    相关推荐

    【C语言进阶】面试题请使用宏定义实现字节对齐

    【C语言进阶】面试题请使用宏定义实现字节对齐
    的头像 发表于 07-11 09:21 2357次阅读
    【C<b class='flag-5'>语言</b>进阶】<b class='flag-5'>面试题</b>:<b class='flag-5'>请使用</b>宏定义<b class='flag-5'>实现</b>字节对齐

    C语言面试题大全

    C语言面试题大全{:1:}{:2:}{:1:}{:1:}{:1:}{:1:}
    发表于 04-10 20:51

    《Visual C# 2008程序设计经典案例设计与实现》---判断主机IP合法性算法

    《Visual C# 2008程序设计经典案例设计与实现》---判断主机IP合法性算法.zip[hide][/hide]
    发表于 05-14 10:16

    java经典面试题深度解析

    回答面试题Int 与Integer的区别第三节 以数据结构挖掘集合面试考点第四节 经典面试题重载与重写第五节 如何回答面试官提问Java的接
    发表于 06-20 15:16

    C语言 经典面试题

    C语言经典面试题目.doc
    发表于 08-05 22:03

    c语言面试题

    c语言面试题集(单片机)C language problem(20151125084232)
    发表于 12-18 14:05 8次下载

    c语言面试题

    c语言面试题
    发表于 11-05 16:48 0次下载

    C语言经典面试题

    面试题
    发表于 12-20 22:41 0次下载

    C语言经典面试题

    C语言 经典面试题
    发表于 01-05 11:27 0次下载

    经典硬件面试题精选及解答

    经典硬件面试题精选及解答
    发表于 11-29 18:02 0次下载

    【C语言经典面试题】sizeof与strlen有什么区别?

    这道经典面试题,我来跟你一起聊一聊。
    的头像 发表于 10-05 16:30 1816次阅读
    【C<b class='flag-5'>语言</b><b class='flag-5'>经典</b><b class='flag-5'>面试题</b>】sizeof与strlen有什么区别?

    【C语言经典面试题】函数指针数组的定义是怎么样的?

    经典面试题,有必要了解下!
    的头像 发表于 10-05 16:35 1990次阅读
    【C<b class='flag-5'>语言</b><b class='flag-5'>经典</b><b class='flag-5'>面试题</b>】函数指针数组的定义是怎么样的?

    【C语言经典面试题】static关键字的作用有哪些?

    经典面试题,有必要了解下!
    的头像 发表于 10-02 12:00 2387次阅读
    【C<b class='flag-5'>语言</b><b class='flag-5'>经典</b><b class='flag-5'>面试题</b>】static关键字的作用有哪些?

    【C语言经典面试题】求数组元素的个数的宏定义

    经典面试题,有必要了解下!
    的头像 发表于 10-02 11:58 2842次阅读
    【C<b class='flag-5'>语言</b><b class='flag-5'>经典</b><b class='flag-5'>面试题</b>】求数组元素的个数的宏定义

    【C语言进阶】面试题请使用代码判断主机存储属于大端模式还是小端模式?

    经典面试题,有必要了解下!
    的头像 发表于 10-02 11:56 2095次阅读
    【C<b class='flag-5'>语言</b>进阶】<b class='flag-5'>面试题</b>:<b class='flag-5'>请使用</b>代码<b class='flag-5'>判断</b>主机存储属于大端模式还是小端模式?