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
|