Namespaces
Variants

strncpy, strncpy_s

From cppreference.net
< 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 が指す文字配列にコピーする。
もし count が配列全体 src がコピーされる前に到達した場合、結果の文字配列はnull終端されません。
src から終端ナル文字をコピーした後、 count に達していない場合、追加のナル文字が dest に書き込まれ、合計で count 文字が書き込まれるまで続きます。
文字配列が重複している場合、 dest または src が文字配列へのポインタでない場合( dest または src がnullポインタの場合を含む)、 dest が指す配列のサイズが count より小さい場合、または src が指す配列のサイズが count より小さく、かつnull文字を含まない場合、動作は未定義です。
2) (1) と同様ですが、以下の点が異なります:この関数は count までパディングするために宛先配列にゼロを書き続けることはせず、終端ナル文字を書き込んだ後で停止します(ソースにナル文字が存在しなかった場合は、 dest [ count ] にナル文字を書き込んで停止します)。また、以下のエラーが実行時に検出され、現在設定されている constraint handler 関数を呼び出します:
  • src または dest がナルポインタの場合
  • destsz がゼロまたは RSIZE_MAX より大きい場合
  • count RSIZE_MAX より大きい場合
  • count destsz 以上であり、かつ destsz strnlen_s ( src, count ) 以下である場合(つまり、切り捨てが発生する場合)
  • ソース文字列と宛先文字列の間にオーバーラップが発生する場合
dest が指す文字配列のサイズが strnlen_s ( src, destsz ) 以下である場合、動作は未定義です。言い換えれば、 destsz の誤った値は差し迫ったバッファオーバーフローを露呈しません。 src が指す文字配列のサイズが strnlen_s ( src, count ) 未満である場合、動作は未定義です。言い換えれば、 count の誤った値はバッファオーバーフローを許容する可能性があります。
すべての境界チェック付き関数と同様に、 strncpy_s は、実装によって __STDC_LIB_EXT1__ が定義されており、かつユーザーが <string.h> を含める前に __STDC_WANT_LIB_EXT1__ を整数定数 1 に定義した場合にのみ利用可能であることが保証されます。

目次

パラメータ

dest - コピー先の文字配列へのポインタ
src - コピー元の文字配列へのポインタ
count - コピーする最大文字数
destsz - 宛先バッファのサイズ

戻り値

1) dest のコピーを返す
2) 成功時はゼロを返し、エラー時は非ゼロを返します。また、エラー時には dest [ 0 ] にゼロを書き込みます(ただし dest がnullポインタの場合、または destsz がゼロまたは RSIZE_MAX より大きい場合を除く)。また、宛先配列の残りの部分を未規定の値で上書きする可能性があります。

注記

C11後のDR 468で修正された通り、 strncpy_s は、 strcpy_s とは異なり、エラーが発生した場合にのみ宛先配列の残りの部分を上書きすることが許可されています。

strncpy とは異なり、 strncpy_s は宛先配列をゼロで埋めません。これは既存のコードを境界チェック版に変換する際の一般的なエラーの原因となります。

宛先バッファに収まるように切り詰めることはセキュリティリスクであり、したがって strncpy_s の実行時制約違反となりますが、 count を宛先配列のサイズから1を引いた値に指定することで、切り詰め動作を実現することが可能です:これは最初の 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"; // null終端文字なし
    strncpy(dest, src, 5); // 5文字 'h', 'i', '\0', '\0', '\0' を 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); // 切り捨て: 2文字 'h', 'i' を 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);  // r1 に 0 を書き込み、6文字を dst1 に書き込む
    printf("dst1 = \"%s\", r1 = %d\n", dst1,r1); // 'h','e','l','l','o','\0' を dst1 に書き込む
    char dst2[5], src2[7] = {'g','o','o','d','b','y','e'};
    errno_t r2 = strncpy_s(dst2, 5, src2, 7);    // コピーが宛先配列をオーバーフロー
    printf("dst2 = \"%s\", r2 = %d\n", dst2,r2); // 0以外を r2 に書き込み、'\0' を dst2[0] に書き込む
    char dst3[5];
    errno_t r3 = strncpy_s(dst3, 5, src2, 4);    // r3 に 0 を書き込み、5文字を dst3 に書き込む
    printf("dst3 = \"%s\", r3 = %d\n", dst3,r3); // 'g', 'o', 'o', 'd', '\0' を 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関数

関連項目

文字列を別の文字列にコピーする
(関数)
バッファを別のバッファにコピーする
(関数)
(dynamic memory TR)
指定されたサイズまでの文字列のコピーを割り当てる
(関数)