已知strcpy函數(shù)的原型是: char *strcpy(char *dst, const char *src);
1.strcpy的實現(xiàn)代碼char * strcpy(char *dst,const char *src) //[1] { assert(dst != NULL && src != NULL); //[2] char *ret = dst; //[3] while ((*dst++=*src++)!='\0'); //[4] return ret; } [1]const修飾 源字符串參數(shù)用const修飾,防止修改源字符串,。 [2]空指針檢查 (A)不檢查指針的有效性,,說明答題者不注重代碼的健壯性。 (B)檢查指針的有效性時使用assert(!dst && !src); char *轉換為bool即是類型隱式轉換,,這種功能雖然靈活,,但更多的是導致出錯概率增大和維護成本升高。 (C)檢查指針的有效性時使用assert(dst != 0 && src != 0); 直接使用常量(如本例中的0)會減少程序的可維護性,。而使用NULL代替0,,如果出現(xiàn)拼寫錯誤,編譯器就會檢查出來,。 [3]返回目標地址 (A)忘記保存原始的strdst值,。 [4]'\0' (A)循環(huán)寫成while (*dst++=*src++);明顯是錯誤的。 (B)循環(huán)寫成while (*src!='\0') *dst++=*src++; 循環(huán)體結束后,,dst字符串的末尾沒有正確地加上'\0',。
2.為什么要返回char *?返回dst的原始值使函數(shù)能夠支持鏈式表達式,。 鏈式表達式的形式如: int l=strlen(strcpy(strA,strB)); 又如: char * strA=strcpy(new char[10],strB); 返回strSrc的原始值是錯誤的,。 其一,源字符串肯定是已知的,,返回它沒有意義,。 其二,不能支持形如第二例的表達式,。 其三,,把const char *作為char *返回,類型不符,,編譯報錯,。
3.假如考慮dst和src內存重疊的情況,strcpy該怎么實現(xiàn)char s[10]="hello"; strcpy(s, s+1); //應返回ello,, //strcpy(s+1, s); //應返回hhello,,但實際會報錯,因為dst與src重疊了,,把'\0'覆蓋了 所謂重疊,,就是src未處理的部分已經(jīng)被dst給覆蓋了,只有一種情況:src<=dst<=src+strlen(src) C函數(shù)memcpy自帶內存重疊檢測功能,,下面給出memcpy的實現(xiàn)my_memcpy,。 char * strcpy(char *dst,const char *src) { assert(dst != NULL && src != NULL); char *ret = dst; my_memcpy(dst, src, strlen(src)+1); return ret; } my_memcpy的實現(xiàn)如下 char *my_memcpy(char *dst, const char* src, int cnt) { assert(dst != NULL && src != NULL); char *ret = dst; if (dst >= src && dst <= src+cnt-1) //內存重疊,,從高地址開始復制 { dst = dst+cnt-1; src = src+cnt-1; while (cnt--) *dst-- = *src--; } else //正常情況,從低地址開始復制 { while (cnt--) *dst++ = *src++; } return ret; } 庫函數(shù)strcpy其實有幾個漏洞
1.傳入的指針沒有非空判斷
代碼: char a[]="hello"; strcpy(a,NULL); 編譯和運行:編譯通過,,運行段錯誤 [root@fedora7 code]# gcc test.c -o test [root@fedora7 code]# ./test Segmentation fault 2.沒有檢查兩個字符串是否以NULL(即'\0')結尾
代碼1: char b[10]="1234567890"; //注意這里的字符串已經(jīng)越界了 strcpy(b,'a'); //這里的2個字符串都沒有結尾標志 編譯和運行:運行段錯誤 [root@fedora7 code]# gcc test.c -o test test.c: In function ‘test’: test.c:61: warning: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast [root@fedora7 code]# ./test Segmentation fault 代碼2: 將代碼1中的 strcpy(b,'a'); 換成 strcpy(b,"a"); 編譯和運行:都沒有問題 [root@fedora7 code]# gcc test.c -o test [root@fedora7 code]# ./test a 3.目標字符串長度<源字符串長度 沒有判斷
代碼: char a[5]="haha"; char b[10]="123456789"; strcpy(a,b); puts(a); puts(b); 編譯和運行:運行段錯誤 [root@fedora7 code]# gcc test.c -o test [root@fedora7 code]# ./test 123456789 123456789 Segmentation fault (這個段錯誤不太好解釋,,沒想明白) 4.代碼實例: //date:20100820
//function:my_strcpy //note:模仿strcpy /* strcpy原型:char *strcpy(char *dstr,const char *sstr); 庫函數(shù)解析:將字符串sstr的字符拷貝到dstr,返回dstr的地址,。(注意返回值) */ char * my_strcpy(char *dstr,const char *sstr); //const說明源字符串為只讀變量
test()
{ char a[]="hello"; char b[32]; my_strcpy(b,a);
puts(b); } char * my_strcpy(char *dstr,const char *sstr)
{ if(!sstr || !dstr) //防止空指針操作 return NULL; #if 0 //方法一 printf("Method A\n"); while(*sstr!='\0') *dstr++=*sstr++; *dstr='\0'; //注意復制時需要加上字符結束標志 #else //方法二 printf("Method B\n"); while((*dstr++=*sstr++)!='\0'); //這里不需要加上字符結束標志,,想想為什么呢? #endif }
main() { test(); } |
|
來自: helloworld441 > 《c/c 》