2.3 標準庫提供的字符串處理函數
C/C++提供了眾多的字符串處理函數,表2-1介紹了主要的字符串處理函數。
表2-1 字符串處理函數

傳遞給這些標準庫函數例程的指針必須具有非零值,并且指向以null結束的字符數組中的第一個元素。其中一些標準庫函數會修改傳遞給它的字符串,這些函數將假定它們所修改的字符串具有足夠大的空間接收本函數新生成的字符,程序員必須確保目標字符串必須足夠大。
2.3.1 strlen
strlen()計算字符數組的字符數,以'\0'為結束標志,計算不為'\0'的數組元素個數。
自定義函數實現strlen的功能是:
int strlen(const char *str){ assert(str != NULL); int len=0; while((*str++) != '\0') len++; return len; }
或不用變量實現此功能
int strlen(const char *str){ assert(str != NULL); return *str == '\0' ? 0 : (1+strlen(++str)); }
例1:下面的程序的輸出是什么?(2010·網易)
int main(void){ int n; char y[10]="ntse"; char *x=y; n=strlen(x); *x=x[n]; x++; printf("x=%s\n", x); printf("y=%s\n", y); return 0; }
解答:該程序的輸出結果為:
x=tse y=
因為n=4,則語句“*x=x[n];”的功能是將x指向的第一個字符'n'修改為'\0',這樣y字符串的第一位為'\0',所以第二個輸出為空;進行x++操作后,x指向第二個字符t,所以第一個輸出為:tse。
注意:printf語句在輸出字符串時,將'\0'當作字符串的結尾。
2.3.2 strcmp
即兩個字符串自左向右逐個字符相比(按ASCII值大小相比較),直到出現不同的字符或遇'\0'為止。如:
"A" < "B" "a" > "A" "computer" > "compare"
自定義函數實現strcmp()函數的功能:
int strcmp (const char * str1, const char * str2){ assert(str1 != NULL && str2 != NULL); int ret=0; while(!(ret=*(unsigned char *)str1- *(unsigned char *)str2) && * str1){ str1++;//++str1; str2++;//++str2; } if(ret<0) ret=-1; else if(ret>0) ret=1; return ret; }
例1:判斷字符串a和b是否相等,應當使用( )?(2012·迅雷)
A.if(a==b)
B.if(a=b)
C.if(strcpy(a,b))
D.if(strcmp(a, b))
解答:D。A比較的是首地址而不是內容。
2.3.3 strcat與strcpy
strcat(dest,src)把src所指字符串添加到dest結尾處(覆蓋dest結尾處的'\0')并添加'\0'。
strcpy(dest,src)把從src地址開始且含有null結束符的字符串復制到以dest開始的地址空間。
傳遞給標準庫函數strcat和strcpy的第一個實參數組必須具有足夠大的空間存放新生成的字符串。
自定義函數實現strcat()函數的功能:
char *strcat(char *strDest, const char *strSrc){ char *address=strDest; assert((strDest != NULL) && (strSrc != NULL)); while(*strDest){ strDest++; } while(*strDest++=*strSrc++); return address; }
自定義函數實現strcpy()函數的功能:
char *strcpy(char *strDestination, const char *strSource){ assert(strDestination != NULL && strSource != NULL); char *strD=strDestination; while ((*strDestination++=*strSource++) != '\0'); return strD; }
strcat與strncat的區別是strncat是將s2的前n個字符連接到s1后面,并返回s1,也即其是利用n作為結束標志,而strcat是利用字符串末尾的空字符作為結束標志。strcpy與strncpy的原理同。
例1:以下哪個說法正確 ?(2012·搜狗)
int func(){ char b[2]={0}; strcpy(b, "aaa"); }
A.Debug版崩潰,Release版正常
B.Debug版正常,Release版崩潰
C.Debug版崩潰,Release版崩潰
D.Debug版正常,Release版正常
解答:A。因為在Debug中有ASSERT斷言保護,所以要崩潰,而在Release中就會刪掉ASSERT,所以會出現正常運行。但是不推薦如此做,因為這樣會覆蓋不屬于自己的內存,這極易導致程序崩潰。
2.3.4 memcpy與memset
1.memcpy
void *memcpy(void *dest, const void *src, size_t n);
功能:從源src所指的內存地址的起始位置開始拷貝n個字節到目標dest所指的內存地址的起始位置中。函數返回指向dest的指針。
例1:下面的代碼可能出現下列哪些運行結果( )?【多選】(2012·中興)
void MyFunc(unsigned char * pucData, unsigned short wLen){ unsigned char aucBuff[MAX_BUFF_LEN]; memcpy(aucBuff, pucData, wLen); }
A.程序運行正常
B.某個全局變量被寫覆蓋
C.aucBuff數組寫越界
D.程序跑飛
解答:AC。aucBuff的內存在棧上,而全局變量存儲在全局(靜態)存儲區,不可能被覆蓋,故B錯。
程序“跑飛”是指系統受到某種干擾后,程序計數器PC的值偏離了給定的唯一變化歷程,導致程序運行偏離正常的運行路徑。程序“跑飛”因素及后果往往是不可預計的。在很多情況下,程序“跑飛”后系統會進入死循環而導致死機,本題代碼不會造成這種后果,故D錯。
例2:請寫出strcpy和memcpy的區別?(2012·海康威視)
解答:strcpy和memcpy都是標準C庫函數,主要有以下3方面的區別:
1)復制的內容不同。strcpy只能復制字符串,而memcpy可以復制任意內容,例如字符數組、整型、結構體、類等。strcpy只用于字符串復制,并且它不僅復制字符串內容之外,還會復制字符串的結束符。memcpy對于需要復制的內容沒有限制,因此用途更廣。
2)復制的方法不同。strcpy不需要指定長度,它遇到被復制字符的串結束符'\0'時才結束,所以容易溢出。memcpy則是根據其第3個參數決定復制的長度。
3)用途不同。通常在復制字符串時用strcpy,而需要復制其他類型數據時則一般用memcpy。
2.memset
void *memset(void *s, int ch, size_t n);
功能:將s中前n個字節用ch替換并返回s,作用是在一段內存塊中填充某個給定的值,它是對較大的結構體或數組進行清零操作的一種最快方法。