strncpy, strncpy_s
提供: cppreference.com
ヘッダ <string.h> で定義 | ||
(1) | ||
char*strncpy(char*dest, constchar*src, size_t count ); | (C99未満) | |
char*strncpy(char*restrict dest, constchar*restrict src, size_t count ); | (C99以上) | |
errno_t strncpy_s(char*restrict dest, rsize_t destsz, constchar*restrict src, rsize_t count); | (2) | (C11以上) |
1)
src
の指す文字配列から最初のヌル文字まで最大 count
個の文字を dest
の指す文字配列にコピーします。dest
の残りはゼロクリアされます (性能の懸念があるかもしれません)。src
の最初の count
個の文字がヌルでない場合、 dest
はヌル終端されません! 文字配列がオーバーラップしている場合、
dest
または src
が文字配列を指すポインタでない場合 (dest
または src
がヌルポインタの場合も含みます)、 dest
の指す配列のサイズが count
より小さい場合、または src
の指す配列のサイズが count
より小さくヌル文字を含まない場合、動作は未定義です。2)
src
の指す文字配列から最初のヌル文字まで最大 count
個の文字を dest
の指す文字配列にコピーします。 その後、ヌル終端を追加します。 そのため
dest
は必ずヌル終端文字列になります。 エラーが検出された場合、
dest
の残りは未規定の値になります。 以下のエラーが実行時に検出され、現在設定されている制約ハンドラ関数を呼びます。
src
またはdest
がヌルポインタ。destsz
またはcount
がゼロまたは RSIZE_MAX より大きい。destsz
が strnlen_s(src, count) より小さいまたは等しい。 別の言い方をすると、切り捨てが発生する。- コピー元とコピー先の文字列間でオーバーラップが発生する。
dest
の指す文字配列のサイズ < strnlen_s(src, destsz) <= destsz
の場合、動作は未定義です。 別の言い方をすると、誤った destsz
の値は切迫したバッファオーバーフローを露呈しません。 src
の指す文字配列のサイズ < strnlen_s(src, count) < destsz
の場合、動作は未定義です。 別の言い方をすると、誤った count
の値は切迫したバッファオーバーフローを露呈しません。 - すべての境界チェック付き関数と同様に、
strncpy_s
は __STDC_LIB_EXT1__ が処理系によって定義されていて、<string.h>
をインクルードする前にユーザが __STDC_WANT_LIB_EXT1__ を整数定数 1 に定義した場合にのみ、利用可能であることが保証されます。
目次 |
[編集]引数
dest | - | コピー先の文字配列を指すポインタ |
src | - | コピー元の文字配列を指すポインタ |
count | - | コピーする最大文字数 |
destsz | - | コピー先バッファのサイズ |
[編集]戻り値
1)
dest
のコピーを返します。2) 成功した場合はゼロを返します。 エラーが発生した場合は非ゼロを返します。 また、エラーの場合は dest[0] にゼロを書き込み (
dest
がヌルポインタでなく、 destsz
がゼロでなく RSIZE_MAX より大きくなければ)、コピー先配列の残りを未規定の値で上書きする可能性があります。[編集]ノート
C11 後の DR 468 で訂正されたように、 strncpy_s
は strcpy_s と異なり、エラーが発生した場合にのみ、コピー先配列の残りを上書きすることが認められています。
strncpy
と異なり、 strncpy_s
はヌル終端文字列関数であり、コピー先配列をゼロクリアしません。 これは既存のコードを Annex K 版に変換するときのよくある誤りの元になります。
コピー先バッファに収まるよう切り捨てることはセキュリティリスクになり、そのため strncpy_s
に対する実行時制約違反になりますが、コピー先配列のサイズより1小さい count
を指定することにより、切り捨て動作を得ることが可能であり、最初の count
バイトをコピーしていつものようにヌル終端を追加します (strncpy_s(dst, sizeof dst, src, (sizeof dst)-1);)。
[編集]例
Run this code
#define __STDC_WANT_LIB_EXT1__ 1#include <string.h>#include <stdio.h>#include <stdlib.h> int main(void){char src[]="hi";char dest[6]="abcdef";// ヌル終端なし。 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";int r1 = strncpy_s(dst1, 6, src1, 100);// 6個の文字 'h','e','l','l','o','\0' を dst1 に書き込みます。printf("dst1 = \"%s\", r1 = %d\n", dst1,r1);// r1 は 0 になります。 char dst2[5], src2[7]={'g','o','o','d','b','y','e'};int r2 = strncpy_s(dst2, 5, src2, 7);// コピー先配列のオーバーフロー。printf("dst2 = \"%s\", r2 = %d\n", dst2,r2);// '\0' が dst2[0] に書き込まれ、 r2 は非ゼロになります。 char dst3[5];int r3 = strncpy_s(dst3, 5, src2, 4);// 5個の文字 'g', 'o', 'o', 'd', '\0' を dst3 に書き込みます。printf("dst3 = \"%s\", r3 = %d\n", dst3,r3);// r3 は 0 になります。#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
[編集]参考文献
- C11 standard (ISO/IEC 9899:2011):
- 7.24.2.4 The strncpy function (p: 363-364)
- K.3.7.1.4 The strncpy_s function (p: 616-617)