結果隔了四天才更新 qwq,前幾天根本忘得一乾二淨 XD(同時適用於三年前及現在)
進入正文吧,今天要介紹的是:
strcpy
、strncpy
:字串複製
所屬標頭檔:<string.h>
函式宣告:
char *strcpy( char *dest, const char *src );
char *strncpy( char *dest, const char *src, size_t count );
先說 strcpy()
,將來源字串(src)複製到目的地(dest),並回傳 dest 指向的字串,要注意的有以下兩點:
- 第一個參數是目的地(dest),第二個是來源(src)
- 會有緩衝區溢位(buffer overflow)的問題
來看看何謂緩衝區溢位:假設有一程式進行了如下宣告:
int i = 5;
char s[8] = "Hi 1234";
那麼這些變數的記憶體配置可能如下:
如果今天我們進行了如下操作:
strcpy(s, "hello sky");
那麼記憶體裡的內容就會變成如下:
於是這時 i 的值就會變成 121,我們可以用以下程式來驗證:
#include <stdio.h>
#include <string.h>
int main(void) {
int i = 5;
char s[8] = "Hi 1234";
printf("address of i: %p\naddress of s: %p\n", &i, s);
strcpy(s, "hello sky");
printf("value of s: %s\nvalue of i: %d\n", s, i);
return 0;
}
參考輸出:
address of i: 000000000061FE1C
address of s: 000000000061FE14
value of s: hello sky
value of i: 121
使用不同的編譯器可能會有不同的結果,這裡筆者用的是 gcc 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)。
為了解決這樣的問題,我們可以改用 strncpy()
,他比 strcpy()
多了一個參數:count,用來控制最多複製幾個字元,而它一樣會回傳 dest 指向的字串。這裡也有些地方要注意:
- 如果 src 字元數(含
\0
)比 count 少,會把剩下未滿 count 的部分通通補上\0
- 如果 src 字元數(含
\0
)比 count 多,他不會幫你補\0
,而是要自己補
strncpy()
的使用可參考以下範例:
#include <stdio.h>
#include <string.h>
int main(void) {
int i = 67; // ASCII 的 'C'
char s[8] = "Hi 1234";
printf("address of i: %p\naddress of s: %p\n", &i, s);
strncpy(s, "hello sky", 8);
printf("value of i: %d\n(1) value of s: %s\n", i, s);
s[7] = '\0'; // 自己補 '\0'
printf("(2) value of s: %s\n", s);
return 0;
}
參考輸出:
address of i: 000000000061FE1C
address of s: 000000000061FE14
value of i: 67
(1) value of s: hello skC
(2) value of s: hello s
Undefined Behavior
在使用這兩個函式時,可能會造成 undefined behavior,以下列舉可能的情況:
strcpy
- 緩衝區溢位(其實是 dest 不夠長)
- dest 和 src 有重疊的部分
- 如果 dest 指到的不是一個字元陣列
- 如果 src 指向的字串沒有以
\0
結尾
strncpy
- dest 和 src 有重疊的部分
- 如果 dest 或 src 其中一個不是指向一個字串
- 如果 dest 不夠長(比 count 短)
- 如果 src 比 count 短而且 src 沒有以
\0
結尾
其實這個部分在 C99 已受到限制:宣告中新增了 restrict
關鍵字,對於這個關鍵字有興趣的人可以自己查查看。
天啊不是我在說,blogger 首頁的文章預覽圖也太醜了吧 qq,而且是發佈後才知道
(新網站就沒這個問題ㄌ)
參考資料:
- cppreference - strcpy
- cppreference - strncpy
- 我休息了 4 天的腦袋