strncpy, strncpy_s
來自 cppreference.com
| 定義於標頭檔案 <string.h> |
||
| (1) | ||
| char *strncpy( char *dest, const char *src, size_t count ); |
(直到 C99) | |
| char *strncpy( char *restrict dest, const char *restrict src, size_t count ); |
(C99 起) | |
| errno_t strncpy_s( char *restrict dest, rsize_t destsz, const char *restrict src, rsize_t count ); |
(2) | (C11 起) |
1) 從
src 指向的字元陣列中複製最多 count 個字元(包括終止空字元,但不包括空字元之後的任何字元)到 dest 指向的字元陣列中。 如果在複製完整個
src 陣列之前達到 count,則結果字元陣列不是以空字元結尾的。 如果從
src 複製終止空字元後,仍未達到 count,則會在 dest 中寫入額外的空字元,直到寫入的總字元數為 count。 如果字元陣列重疊,如果
dest 或 src 不是指向字元陣列的指標(包括 dest 或 src 為空指標),如果 dest 指向的陣列大小小於 count,或者如果 src 指向的陣列大小小於 count 且不包含空字元,則行為是未定義的。2) 與 (1) 相同,但函式不再將零寫入目標陣列以填充到
count,而是在寫入終止空字元後停止(如果源中沒有空字元,它會在 dest[count] 處寫入一個然後停止)。此外,以下錯誤會在執行時檢測到並呼叫當前安裝的 約束處理函式- `src` 或 `dest` 是空指標
-
destsz為零或大於 RSIZE_MAX -
count大於 RSIZE_MAX -
count大於或等於destsz,但destsz小於或等於 strnlen_s(src, count),換句話說,會發生截斷 - 源字串和目標字串之間會發生重疊
如果
dest 指向的字元陣列的大小 < strnlen_s(src, destsz) <= destsz,則行為是未定義的;換句話說,錯誤的 destsz 值不會暴露即將發生的緩衝區溢位。如果 src 指向的字元陣列的大小 < strnlen_s(src, count) < destsz,則行為是未定義的;換句話說,錯誤的 count 值不會暴露即將發生的緩衝區溢位。- 與所有邊界檢查函式一樣,只有當實現定義了 __STDC_LIB_EXT1__ 並且使用者在包含 <string.h> 之前將 __STDC_WANT_LIB_EXT1__ 定義為整數常量 1 時,才能保證
strncpy_s可用。
目錄 |
[編輯] 引數
| dest | - | 指向要複製到的字元陣列的指標 |
| src | - | 指向要複製來源的字元陣列的指標 |
| count | - | 要複製的最大字元數 |
| destsz | - | 目標緩衝區的尺寸 |
[編輯] 返回值
1) 返回 `dest` 的副本
2) 成功時返回零,錯誤時返回非零。此外,在錯誤時,將零寫入 dest[0](除非
dest 是空指標或 destsz 為零或大於 RSIZE_MAX),並且可能會用未指定的值覆蓋目標陣列的其餘部分。[編輯] 注意
根據 C11 後 DR 468 的修正,strncpy_s,與 strcpy_s 不同,只允許在發生錯誤時覆蓋目標陣列的其餘部分。
與 strncpy 不同,strncpy_s 不會用零填充目標陣列。這在將現有程式碼轉換為邊界檢查版本時,是一個常見的錯誤來源。
儘管截斷以適應目標緩衝區是一種安全風險,因此對於 strncpy_s 而言是執行時約束違規,但透過將 count 指定為目標陣列大小減一,可以獲得截斷行為:它將複製前 count 個位元組並始終附加空終止符:strncpy_s(dst, sizeof dst, src, (sizeof dst)-1);
[編輯] 示例
執行此程式碼
#define __STDC_WANT_LIB_EXT1__ 1 #include <string.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> int main(void) { char src[] = "hi"; char dest[6] = "abcdef"; // no null terminator strncpy(dest, src, 5); // writes five characters 'h', 'i', '\0', '\0', '\0' to dest printf("strncpy(dest, src, 5) to a 6-byte dest gives : "); for (size_t n = 0; n < sizeof dest; ++n) { char c = dest[n]; c ? printf("'%c' ", c) : printf("'\\0' "); } printf("\nstrncpy(dest2, src, 2) to a 2-byte dst gives : "); char dest2[2]; strncpy(dest2, src, 2); // truncation: writes two characters 'h', 'i', to dest2 for (size_t n = 0; n < sizeof dest2; ++n) { char c = dest2[n]; c ? printf("'%c' ", c) : printf("'\\0' "); } printf("\n"); #ifdef __STDC_LIB_EXT1__ set_constraint_handler_s(ignore_handler_s); char dst1[6], src1[100] = "hello"; errno_t r1 = strncpy_s(dst1, 6, src1, 100); // writes 0 to r1, 6 characters to dst1 printf("dst1 = \"%s\", r1 = %d\n", dst1,r1); // 'h','e','l','l','o','\0' to dst1 char dst2[5], src2[7] = {'g','o','o','d','b','y','e'}; errno_t r2 = strncpy_s(dst2, 5, src2, 7); // copy overflows the destination array printf("dst2 = \"%s\", r2 = %d\n", dst2,r2); // writes nonzero to r2,'\0' to dst2[0] char dst3[5]; errno_t r3 = strncpy_s(dst3, 5, src2, 4); // writes 0 to r3, 5 characters to dst3 printf("dst3 = \"%s\", r3 = %d\n", dst3,r3); // 'g', 'o', 'o', 'd', '\0' to dst3 #endif }
可能的輸出
strncpy(dest, src, 5) to a 6-byte dst gives : 'h' 'i' '\0' '\0' '\0' 'f' strncpy(dest2, src, 2) to a 2-byte dst gives : 'h' 'i' dst1 = "hello", r1 = 0 dst2 = "", r2 = 22 dst3 = "good", r3 = 0
[編輯] 參考
- C17 標準 (ISO/IEC 9899:2018)
- 7.24.2.4 strncpy 函式 (p: 265)
- K.3.7.1.4 strncpy_s 函式 (p: 447-448)
- C11 標準 (ISO/IEC 9899:2011)
- 7.24.2.4 strncpy 函式 (p: 363-364)
- K.3.7.1.4 strncpy_s 函式 (p: 616-617)
- C99 標準 (ISO/IEC 9899:1999)
- 7.21.2.4 strncpy 函式 (p: 326-327)
- C89/C90 標準 (ISO/IEC 9899:1990)
- 4.11.2.4 strncpy 函式
[編輯] 另請參閱
| (C11) |
將一個字串複製到另一個字串 (函式) |
| (C11) |
將一個緩衝區複製到另一個緩衝區 (函式) |
| (動態記憶體 TR) |
分配一個指定大小的字串副本 (函式) |
| C++ 文件 適用於 strncpy
| |