说明:最近编写代码时,需要用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; }
运行结果:
此时,运行结果与想象宏的结果一致。。
原文地址:https://www.cnblogs.com/gykai/p/9976990.html