名稱空間
變體
操作

strncpy, strncpy_s

來自 cppreference.com
< c‎ | string‎ | byte
定義於標頭檔案 <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
如果字元陣列重疊,如果 destsrc 不是指向字元陣列的指標(包括 destsrc 為空指標),如果 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 函式

[編輯] 另請參閱

將一個字串複製到另一個字串
(函式) [編輯]
將一個緩衝區複製到另一個緩衝區
(函式) [編輯]
(動態記憶體 TR)
分配一個指定大小的字串副本
(函式) [編輯]
C++ 文件 適用於 strncpy