C裡操作字串很高效,但也很麻煩。
1. char * strcpy ( char * destination, const char * source );
最常用的函數,但是卻不安全,原因在於,一是要destination有足夠的空間,二是要保證source和destination指向的空間沒有overlap。
2. int sprintf ( char * str, const char * format, ... );
也許要問,這個怎麼用於字串拷貝呢?可以這麼用 sprintf(dest, "%s", src); 但是要調用者保證dest有足夠的記憶體存放src。
3. char * strncpy ( char * destination, const char * source, size_t num );
比起strcpy,多了個長度的控制。從source拷貝num個字元到destination。如果source裡不夠num字元怎麼辦呢?會補充0。
一個典型的用法是:
char buf[MAX];
strncpy(buf, src, MAX-1);
這段代碼的本意是,一個長為MAX的buf,最多也就放MAX-1個字元,最後一個位置放‘\0'。因此最多能從src裡拷貝MAX-1個字元,如果src裡沒這麼多,剩餘的填充0就是了。
但是這樣做就安全了嗎?不是,如果src剛好MAX-1個字元。注意到strncpy只複製了MAX-1個字元,最後一個位置未知,有潛在的隱患。下段代碼可以詮釋:
#define MAX 4
char buf[MAX];
char* src="123";
memset(buf, 'x', MAX);
// solution 1. memset(buf, 0, MAX);
strncpy(buf, src, MAX-1);
// solution 2. buf[MAX-1] = '\0';
printf("%s\n", buf);
有兩個辦法可以解決:1. 調用strncpy之前memset為0,有點浪費。2. 在strncpy之後對最後一個字元賦值為0。
都可以,但不夠優雅。
4. int snprintf( char *buffer, int buff_size, const char *format, ... );
用作字串拷貝的用法:
char buf[MAX];
snprintf(buf, sizeof(buf), "%s", src);
即安全,又簡潔。
你可能會關心:如果src的長度大於dest(buf)呢?這個是另外一個問題,這裡需要的是安全的字串拷貝,在C語言裡,如果一個字串指標指向的記憶體沒有結尾字元'\0',是非常危險的。
snprintf會把buf的最後一個位置保留為'\0'。
關於傳回值:如果當前buf夠用,返回實際寫入的字元數;如果不夠用,返回將要寫入的字元數。換句話說,傳回值就是傳入的字元數目。
假設當前的buf[4].
待寫入 實際寫入 傳回值
12 12 2 夠用
123 123 3 夠用
1234 123 4 不夠用
12345 123 5 不夠用
sprintf/snprintf的另外一個用法:
itoa不是ANSI C或C++的一部分,可以變相的用sprintf來代替:
sprintf(str,"%d",value) converts to decimal base.
sprintf(str,"%x",value) converts to hexadecimal base.
sprintf(str,"%o",value) converts to octal base.