**C语言编程实现对IPV4地址的合法性判断**
(资料图片)
> 有了解过我的朋友,可能有点印象,我在N年前的博客中,就写了这个主题,当时确实是工作中遇到了这个问题。本想着等工作搞完之后,就把这个问题的解决代码补上,结果一鸽,就是好几年,真是惭愧。现在把这部分代码公开,欢迎大家来下载测试。
@[toc]# 1 写在前面
有了解过我的朋友,可能有点印象,我在N年前的博客中,就写了这个主题,当时确实是工作中遇到了这个问题。本想着等工作搞完之后,就把这个问题的解决代码补上,结果一鸽,就是好几年,真是惭愧。现在把这部分代码公开,欢迎大家来下载测试。
如果你发现代码有问题,欢迎与我私信联系。
# 2 需求分析
其实,本专题的需求很简单,就是输入一段字符串,判断它是不是合法的IPv4地址。仅仅从功能上看,似乎很简单,但是真正要做到很完美,也是需要下点功夫的。不信,你看看下文的拆解。

# 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.1check 192.168.0.1ret 1~/ipv4]$./testcheck 192.168.w.2ret 0```
但是,如果我加一个限制:如何判断一个IPV4地址是一个合法的 **主机地址** 呢?
比如这个:“238.171.84.41”,它的判断还是合法的哦,实际上这不是合法的 **主机地址** 。
```c~/ipv4]$./test 238.171.84.41check 238.171.84.41ret 1```
另外一个,上面的代码还检测不到,诸如此类的输入:“0192.168.1.1”
```c~/ipv4]$./test 0192.168.1.1check 0192.168.1.1ret 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.1check 0192.168.1.1ret 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地址的类别判断。
在上面的判断返回前,增加一个判断:
```cif (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.41check 238.171.84.41This is not a Class A, B, or C IP address.ret 0
~/ipv4]$./test 192.168.2.3check 192.168.2.3This 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.110.0.0.1172.16.0.1255.255.255.255
非法的测试输入256.0.0.1192.168.0.0.1192.168.0192.168.0.1.2
非法的测试输入256.0.0.1192.168.0.0.1192.168.0192.168.0.1.2300.300.300.3001.2.31.2.3.4.51.2.3.4..1.2.3.41..2.3.4```
测试用例是不断丰富的,欢迎大家来补充。审核编辑黄宇
同花顺数据中心显示,盛讯达5月15日获融资买入298 10万元,占当日买入金额的12 5%,当前融资余额1 89亿元,
1、歌曲名称:爱情歌手名称:莫文蔚(若不是因为爱着你)怎么会夜深还没睡意每个念头都关於你我想你想你好
搜狐体育消息,北京时间5月16日,瑞士草蜢俱乐部官方发布视频,宣布张琳艳荣膺22 23赛季瑞士女超金球奖!!
央视网消息:这两天,广西防城港东兴市一万多亩的红姑娘,也就是红薯迎来大丰收。现在,总台记者杨祉禛就在
1、矿物名称:镜铁矿(赤铁矿变种、与石英伴生)(Hematitevar SpeculariteandQuartz)::矿物概述化学组成:Fe2O3,
近日,阳女士来到农行桂林临桂人民支行,将一面写着“心系百姓,感恩有你”的锦旗送给农行桂林临桂人民支行
由于美股走低,数据显示,2022年标准普尔500上市公司中约有三分之二的高管在年底获得的实际薪酬低于其薪酬
□金陵晚报 紫金山新闻记者邢虹炎炎夏日就要到了,晚间约上三五好友,一起喝点啤酒撸个串,不失为一桩美事
今日,湖人球星詹姆斯在球队训练结束后接受了媒体采访。谈到本赛季的掘金与2020年的不同,詹姆斯表示:“现
1、《张公案》百度网盘txt最新全集下载链接:提取码:jddq张公案(大风刮过创作的长篇小说)小说主要讲述礼部侍
X 关闭
郑州昨天新增确诊病例11例,累计报告确诊病例103例
郑州:各核酸检测采样点开辟学生绿色通道
为何持续多轮做核酸检测 河南疾控专家解释
驻马店:关于依法严厉打击涉疫情网络谣言等违法信息的通告
郑州本轮累计报告103例本土确诊病例 均为普通型或轻型
郑州第五轮9区全员核酸检测已检724.9万人,已确诊5例
X 关闭