说明: 最近编写代码时, 需要用 C 语言实现设置 ip 地址的功能, 奈何本人所涉及的能力有限, 通过网上查阅, 找到了一个可以使用的程序代码, 其中, 有个检查 ip 地址是否有效的函数, 但该函数却存在着一些不安全性, 恰同时我刚好需要该函数, 因此, 我对该函数进行了一些优化, 在此, 想分享一下自己在优化该程序过程中的一些想法和思路. 借此, 希望能够和各位前辈进行交流. 其中, 原代码编写者的博客地址是: https://blog.csdn.net/lihuibo128/article/details/43668065 .
如果该代码还存在着不足, 希望各位前辈能够批评指正.
一, 源程序函数
包含的头文件:
- #include<stdio.h>
- #include<stdlib.h>
- #include<unistd.h>
- #include<string.h>
- #include<string.h>
- #include<regex.h>
源程序:
- /*
- 函数返回值:
- 0 : 成功
- -1 : 失败
- */
- int check_right_ip(const char *ip)
- {
- int status = 0;
- int cflags = REG_EXTENDED;
- regmatch_t pmatch[1];
- const size_t nmatch = 1;
- regex_t reg;
- char str_ip[30] = "";
- const char *pattern = "[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}";// 存在局限
- strcpy(str_ip, ip);
- regcomp(®, pattern, cflags);
- status = regexec(®,str_ip,nmatch,pmatch,0);
- if(status==REG_NOMATCH)
- {
- printf("No match\n");
- return -1;
- }
- else if(status == 0)
- {
- return 0;
- }
- regfree(®);
- return 0;
- }
说明: 在源程序中, 所使用的是利用正则表达式来进行数据位的有效检测, 关于正则表达式函数的的用法, 由于本篇主要侧重点在于代码的优化, 在此, 并不多详细讲解. 可以参考网上其他博主的相关介绍. 该程序的测试主程序如下:
- int main()
- {
- char *ip = "192.168.1.12";
- int res = 0;
- res = check_right_ip(ip);
- if (res == -1)
- {
- fprintf(stdout, "the format of ip is wrong...\r\n");
- return -1;
- }
- fprintf(stdout, "the format of ip is right\r\n");
- return 0;
- }
运行结果:
通过运行结果, 可以看到, 该程序运行正常.
二, 程序的优化之数据有效性的检测
通过上述的简单测试, 可以看到, 该程序可以正常运行, 但却存在着一些潜在的 bug. 首先, 我们都知道, IP 的有效格式是:"192.168.1.12", 但比如有一天有人想输入的 ip 地址是:"192.168.1.12.12", 那么该程序的的运行结果是怎么的呢, 如下是测试的主程序:
- int main()
- {
- char *ip = "192.168.1.12.12";
- int res = 0;
- res = check_right_ip(ip);
- if (res == -1)
- {
- fprintf(stdout, "the format of ip is wrong...\r\n");
- return -1;
- }
- fprintf(stdout, "the format of ip is right\r\n");
- return 0;
- }
编译运行之后的结果如下:
通过结果发现, 该程序竟然运行正确, 但这是我们想要的结果吗? 结果是否定的, 因此, 我们需要考虑如果避免这种情况, 通过对比两个 ip 地址我们可以发现, 其中的点 "." 的个数是不一样的, 因此, 我们可以来计算该点的个数来判断一下 ip 地址的有效性. 修改之后的 check_right_ip() 的函数如下:
- /*
- 函数返回值:
- 0 : 成功
- -1 : 失败
- */
- int check_right_ip(const char *ip)
- {
- int status = 0;
- int cflags = REG_EXTENDED;
- regmatch_t pmatch[1];
- const size_t nmatch = 1;
- regex_t reg;
- char str_ip[30] = "";
- const char *pattern = "[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}";// 存在局限
- /**************new add **********************/
- char *pNext = NULL;
- char *pTmp = NULL;
- int count = 0;
- strcpy(str_ip, ip);
- regcomp(®, pattern, cflags);
- status = regexec(®, str_ip, nmatch, pmatch, 0);
- if(status == REG_NOMATCH)
- {
- printf("No match\n");
- return -1;
- }
- regfree(®);
- pNext = (char *)ip;
- while (1)
- {
- pTmp = strchr(pNext, '.');
- if (pTmp == NULL)
- {
- if (count != 3)
- {
- return -1;
- }
- if (count == 3)
- {
- break;
- }
- }
- count++;
- pNext = pTmp + 1;
- }
- return 0;
- }
说明: 在该函数中, 我们增加了两个了指针, 来进行数据位的有效计算 "." 的个数, 然后根据 "." 的个数来判断其是否有效. 下面是修改之后程序的运行结果
此时, 可以看出, 该程序的的运行结果与我们预期的结果一致, 但这就结果这个问题了吗?? 考虑这么一种情况, 假如有人小手一抖, 只是在 ip 地址中, 多增加了一个 ".", 并没有在其后面添加数字, 那么此时运行结果如下呢? 下面我们来测试一下. 主程序的代码如下:
- int main()
- {
- char *ip = "192.168.1.12.";
- int res = 0;
- fprintf(stdout, "ip = %s\r\n", ip);
- res = check_right_ip(ip);
- if (res == -1)
- {
- fprintf(stdout, "the format of ip is wrong...\r\n");
- return -1;
- }
- fprintf(stdout, "the format of ip is right\r\n");
- return 0;
- }
运行结果如下:
额, 该程序能够运行出正确的结果. 但本人在测试时, 且发现, 有时候并不能正确运行出结果, 当时提示的错误信息是, 段错误. 通过排查发现, 是 check_right_ip() 中的 pNext = pTmp + 1; 这句话导致的, 原因如下, 当指针 pTmp 指向其最后一个 "." 时, pNexr = pTmp + 1; 会指向其末尾, 再此使用 strchr() 函数时, 就会导致段错误. 此时, 有两种方法解决, 一种就是在 pNext = pTmp + 1; 之后, 判断 pNext 是否等于'\0', 另一种则是让 pNext 最初指向 str_ip, 而不是指向 ip, 因为 str_ip 数组中, 末尾全部为'\0', 使用 strchr() 时, 不会导致指向不该指向的地址.
修改之后的 check_right_ip() 的函数如下:
- /*
- 函数返回值:
- 0 : 成功
- -1 : 失败
- */
- int check_right_ip(const char *ip)
- {
- int status = 0;
- int cflags = REG_EXTENDED;
- regmatch_t pmatch[1];
- const size_t nmatch = 1;
- regex_t reg;
- char str_ip[30] = "";
- const char *pattern = "[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}";// 存在局限
- /**************new add **********************/
- char *pNext = NULL;
- char *pTmp = NULL;
- int count = 0;
- strcpy(str_ip, ip);
- regcomp(®, pattern, cflags);
- status = regexec(®, str_ip, nmatch, pmatch, 0);
- if(status == REG_NOMATCH)
- {
- printf("No match\n");
- return -1;
- }
- regfree(®);
- /**************new add **********************/
- pNext = (char *)ip;
- while (1)
- {
- pTmp = strchr(pNext, '.');
- if (pTmp == NULL)
- {
- if (count != 3)
- {
- return -1;
- }
- if (count == 3)
- {
- break;
- }
- }
- count++;
- pNext = pTmp + 1;
- if (*pNext == '\0')
- {
- return -1;
- }
- }
- return 0;
- }
此时, 我们就将其格式讨论完了, 但是, 假如我们输入的 ip 地址是:"192.168.278.12" 时呢? 从实际情况上出发, 该字符串是不符合 ip 地址规范的, 我们来具体的测试一下:
主程序源码:
- int main()
- {
- char *ip = "192.168.1.278";
- int res = 0;
- fprintf(stdout, "ip = %s\r\n", ip);
- res = check_right_ip(ip);
- if (res == -1)
- {
- fprintf(stdout, "the format of ip is wrong...\r\n");
- return -1;
- }
- fprintf(stdout, "the format of ip is right\r\n");
- return 0;
- }
运行结果:
我们发现, 其结果与我们想的不同, 想来原因也是, 我们使用正则表达式来进行判断时, 并没有对其进行数字大小的判断, 因此, 我们需要对其数据的有效性进行判断, 修改之后的源码如下:
check_right_ip 源码:
- int check_right_ip(const char *ip)
- {
- int status = 0;
- int cflags = REG_EXTENDED;
- regmatch_t pmatch[1];
- const size_t nmatch = 1;
- regex_t reg;
- char str_ip[30] = "";
- const char *pattern = "[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}";// 存在局限
- /**************new add **********************/
- char *pNext = NULL;
- char *pTmp = NULL;
- int count = 0;
- char tmpBuf[4] = {0};
- strcpy(str_ip, ip);
- regcomp(®, pattern, cflags);
- status = regexec(®, str_ip, nmatch, pmatch, 0);
- if(status == REG_NOMATCH)
- {
- printf("No match\n");
- return -1;
- }
- regfree(®);
- /**************new add **********************/
- pNext = (char *)ip;
- while (1)
- {
- pTmp = strchr(pNext, '.');
- if (pTmp == NULL)
- {
- if (count != 3)
- {
- return -1;
- }
- if (count == 3)
- {
- break;
- }
- }
- count++;
- pNext = pTmp + 1;
- if (*pNext == '\0')
- {
- return -1;
- }
- }
- pNext = (char *)str_ip;
- while (count--)
- {
- pTmp = strchr(pNext, '.');
- if((pTmp - pNext) == 3)
- {
- strncpy(tmpBuf, pNext, 3);
- if (atoi(tmpBuf)> 255)
- {
- return -1;
- }
- memset(tmpBuf, 0, sizeof(tmpBuf));
- }
- pNext = pTmp + 1;
- }
- return 0;
- }
运行结果:
此时, 运行结果与想象宏的结果一致..
来源: http://www.bubuko.com/infodetail-2851505.html