strcpy 不檢查緩衝區大小,易導致溢位char *strcpy(char *restrict dest, const char *restrict src);
src 指向的字串(含 '\0')複製到 destdest(鏈式呼叫用)dest 空間不足、記憶體重疊char *my_strcpy_v1(char *dest, const char *src) {
char *ret = dest;
while ((*dest++ = *src++) != '\0');
return ret;
}
缺陷:無空指標檢查、無緩衝區長度檢查、dest 必須可寫。
char *my_strcpy_v2(char *dest, const char *src) {
if (!dest || !src) return NULL; // 空指標防護
char *ret = dest;
while ((*dest++ = *src++) != '\0'); // 複製含結束符
return ret;
}
/* 回傳 0 成功,非 0 失敗(ERANGE/EINVAL) */
int my_strcpy_s(char *dest, size_t destsz, const char *src) {
if (!dest || !src || destsz == 0) return EINVAL;
size_t i = 0;
for (; i < destsz - 1 && src[i] != '\0'; ++i)
dest[i] = src[i];
if (i == destsz - 1 && src[i] != '\0') { // 空間不足
dest[0] = '\0';
return ERANGE;
}
dest[i] = '\0';
return 0;
}
while ((*dest++ = *src++) != '\0')*src++:取得當前字元,src 後移*dest++ = ...:寫入當前位置,dest 後移!= '\0':判斷剛寫入的字元是否為結束符'\0' → 繼續迴圈;若是 → 結束符已寫入,迴圈結束關鍵洞察:賦值運算式的值是被賦予的值,因此迴圈條件天然包含「複製並檢查結束符」的雙重語意。
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest1[20], dest2[20], dest3[10]; // 最後一個故意太小
// 版本 2 測試
my_strcpy_v2(dest1, src);
printf("v2: %s\n", dest1);
// 安全版測試
int r = my_strcpy_s(dest2, sizeof(dest2), src);
printf("v3 (normal): %s, ret=%d\n", dest2, r);
r = my_strcpy_s(dest3, sizeof(dest3), src); // 空間不足
printf("v3 (overflow): '%s', ret=%d (ERANGE=%d)\n", dest3, r, ERANGE);
return 0;
}
memcpy + 向量化指令(SSE/AVX/NEON)按 16/32/64 位元組塊複製strlen + memcpy 兩階段:先算長度再大塊複製,利用 CPU 預取器src 與 dest 不重疊,啟用積極優化'\0' 複製memmove 語意)未處理src 可能被並發修改