網友的力量是強大的,昨天發了一篇Post,關於一道面試/筆試題。得到網友們的眾多解決方法。我不得不承認自己寫的代碼是如此的爛。盡管如此,也是很有必要和大家一起來探討,也有必要寫出自己心中所想。這樣才有進步,才有改變,才能將自己的爛代碼優化。接着發一段爛代碼,希望學習網友們更加優美,優秀的代碼。
筆試題目
判斷一個字符串是否是IPv4地址。如果是返回ture,否則返回false。同樣不可以使用庫函數。可以選擇用C/C++,C#或者Java。
e.g. C/C++: bool checkIPv4(char * ip){}
解決方法
鄙人是這樣想的,按照‘.’先將每個字串分割出來。如“192.168.203.70”分割為192,168,203,70四個整型。然后再判斷這四個整型的范圍,是否在0~255之間。我總覺得這種考慮欠妥,應該選擇類似正則表達式那樣的方法吧。但是不會寫。。。
一開始我是這樣寫的。

#include <stdio.h> bool checkIpv4(char * ip) { char *p=ip; char *q=ip; char *c; int i=0,s,count=0; if(*p=='.') //處理特殊情況 return false; while(*p!='\0') { if(*p=='.'||*(p+1)=='\0') //根據'.'將字符串切割出來 { count++; //計算切割的字串個數 if(*(p+1)=='\0') //處理最后一個字串 { i++; q=p; } else q=p-1; s=0; for(int j=1;j<=i;j++) //將切割出來的字串變成整型 { int x=*q-'0'; //字符減'0'變為整型 for(int k=1;k<j;k++) x*=10; s+=x; q--; } printf("%d\n",s); if(s<0||s>255) //判斷切割出來的字串是否在ipv4范圍內 return false; i=0; } else { i++; } p++; } if(count==4) return true; else return false; } int main(void) { char ip[]="a.v.0.0"; if(checkIpv4(ip)) printf("該地址是IPv4地址\n"); else printf("該地址不是IPv4地址\n"); return 0; }
但是很明顯是有問題的。
當檢驗“192.168.203.70”的時候,結果是可以的。
但是當檢驗的對象不是數字的時候,例如“a.168.203.70”,居然也可以驗證通過,欠考慮了。
所以在切割出來的每個整型,我再檢查了一遍每個整型是否在0~9范圍內,不是的話返回false。
if(x<0||x>9) //判斷x是否在0~9之間 return false;
感謝網友zdd的提醒,確實沒有考慮到類型“1...3”出現連續點的情況。果然自己寫的東西夠爛的。我是這樣處理的:
出現這樣的情況是因為
s=0; for(int j=1;j<=i;j++) //將切割出來的字串變成整型 { int x=*q-'0'; //字符減'0'變為整型 if(x<0||x>9) //判斷x是否在0~9之間 return false; for(int k=1;k<j;k++) //第幾位乘以幾-1個10. x*=10; s+=x; q--; }
里面的for循環會發生不執行的情況,所以就不處理類似“1...3”出現連續點的情況了。我改變代碼如下
s=0; int x=-1; for(int j=1;j<=i;j++) //將切割出來的字串變成整型 { x=*q-'0'; //字符減'0'變為整型 if(x<0||x>9) //判斷x是否在0~9之間 return false; for(int k=1;k<j;k++) //第幾位乘以幾-1個10. x*=10; s+=x; q--; } if(x==-1) return false;//防止類型“1...3”出現連續點的情況
將x放在for循環外面,用來檢測是否出現連續個點的情況。
下面是完整的代碼
#include <stdio.h> bool checkIpv4(char * ip) { printf("檢驗對象是:%s\n",ip); char *p=ip; //遍歷指針 char *q=ip; //字串指針 int i=0,s,count=0; //i是每個字串的長度,s是字串轉化為的整型,count是字串的個數 if(*p=='.') //處理特殊情況 return false; while(*p!='\0') //遍歷每個字符 { if(*p=='.'||*(p+1)=='\0') //根據'.'將字符串切割出來,最后一個字串根據'\0'識別 { count++; //計算切割的字串個數 if(*(p+1)=='\0') //處理最后一個字串,‘\0’識別的時候 { i++; q=p; } else q=p-1; //‘.切割’ s=0; int x=-1; for(int j=1;j<=i;j++) //將切割出來的字串變成整型 { x=*q-'0'; //字符減'0'變為整型 if(x<0||x>9) //判斷x是否在0~9之間 return false; for(int k=1;k<j;k++) //第幾位乘以幾-1個10. x*=10; s+=x; q--; } if(x==-1) return false;//防止類型“1...3”出現連續點的情況 printf("%d\n",s); if(s<0||s>255) //判斷切割出來的字串是否在ipv4范圍內 return false; i=0; } else { i++; } p++; } if(count==4) //檢查是否是四個字串 return true; else return false; } int main(void) { char ip[]="1..2.3"; if(checkIpv4(ip)) printf("該地址是IPv4地址\n"); else printf("該地址不是IPv4地址\n"); return 0; }
解釋應該挺清楚的了。這個時候只要切割出來的字符不在0~9范圍內,都不會通過。
相信有更好的解決方法,求共勉之。。。。