ユーニックス総合研究所

  • home
  • archives
  • c-string-copy

C言語の文字列をコピーする【strcpy, snprintf, memcpy, memmove】

  • 作成日: 2024-03-15
  • 更新日: 2024-03-15
  • カテゴリ: C言語

C言語の文字列をコピーしたい場合はstrcpy()などの関数を使います。
この記事ではこれらの関数の使い方などを解説します。

C言語や他の言語を扱うYoutubeも公開しています。
興味がある方は以下のリンクからご覧ください。

Youtubeの当チャンネル

配列の定義時に文字列リテラルをコピーする

char str[] = "Hello";  
printf("%s\n", str);  // Hello  

文字列の配列の定義時に配列を文字列リテラルで初期化することができます。
上記のように初期化を行うと文字列strHelloで初期化されます。

strに格納される文字列はコピーされたものなので、変更も可能です。
文字列リテラルは変更不可ですのでこの辺は注意してください。

str[0] = 'M';  

strcpyで文字列をコピーする

const char *s1 = "Hello";  
char s2[100];  
strcpy(s2, s1);  
printf("%s\n", s2);  // Hello  

strcpy()関数は第1引数に第2引数の文字列をコピーします。
第1引数のポインタには配列を指定しますが、この配列は十分な大きさを持っている必要があります。

というのは、strcpy()はコピー先の配列のサイズ情報を持っていません。
ですので文字列が長くて配列が短かった場合は、バッファオーバーランなどのバグになります。

strcpy()は返り値として第1引数のバッファのポインタを返します。

strcpy()はあまりセキュアな関数ではないです。
ですので可能であればsnprintf()の使用を検討してください。

snprintfで文字列をコピーする

const char *s1 = "Hello";  
char s2[100];  
snprintf(s2, sizeof s2, "%s", s1);  
printf("%s\n", s2);  // Hello  

snprintf()はバッファに書式で整形したデータをコピーします。
snprintf()の第1引数にはバッファへのポインタ、第2引数にはバッファのサイズ、第3引数には書式、第4引数以降には書式にパースさせる引数を渡します。

int snprintf(バッファ, バッファのサイズ, 書式, 書式の引数, ...);  

snprintf()は返り値として合成した文字列の長さを返します。

snprintf()はバッファのサイズを指定できますのでstrcpy()よりはセキュアな関数です。
バッファのサイズ以上の書き込みをしませんので安全に使います。
もっともバッファのサイズの指定を間違えた場合は脆弱性になる可能性があります。

memcpyで文字列をコピーする

const char *s1 = "Hello";  
char s2[100];  
memcpy(s2, s1, strlen(s1) + 1);  
printf("%s\n", s2);  // Hello  

memcpy()関数は第1引数のバッファに第2引数のデータをコピーします。
コピーするサイズは第3引数に指定します。

memcpy()は文字列のコピーではあまり使われる関数ではありません。
しかし使い方によって文字列のコピーにも使えます。

第3引数のサイズには文字列の長さとナル文字分を加えます。
strlen()はナル文字を含めた長さは返しませんので、ナル文字をコピーする場合はそのナル文字分の長さを考慮する必要があります。

memcpy()関数は第1引数と第2引数のバッファが被っていたらその動作は保証されません。
つまり同じアドレスを使ってはダメです。

memcpy関数は返り値としてvoid *型のポインタを返しますがこれは第1引数のバッファへのポインタです。

memmoveで文字列をコピーする

const char *s1 = "Hello";  
char s2[100];  
memmove(s2, s1, strlen(s1) + 1);  
printf("%s\n", s2);  // Hello  

memmove()関数の使い方はmemcpy()と同じです。
使い方については先述のmemcpy()を参照してください。

memcpy()memmove()の違いはmemmove()は第1引数と第2引数のバッファが被っていても動作が保証されることです。
そのためmemcpy()よりもセキュアな関数と言えます。

for文で文字列をコピーする

const char *s1 = "Hello";  
char s2[100];  
int i;  

for (i = 0; i < 99 && i < strlen(s1); i++) {  
    s2[i] = s1[i];  
}  
s2[i] = '\0';  

printf("%s\n", s2);  // Hello  

for文で文字列をコピーするサンプルは上記になります。
文字列s1s2にコピーします。
カウント変数iをカウントしてs2[i]の位置にs1[i]をコピーしています。

for文の条件式は「i < 99 && i < strlen(s1)」になっています。
これはs2のサイズが100なのでナル文字分を引いて99にしています。
またstrlen()で文字列の長さを得て、それよりもカウント変数が上回らないようにしています。

strlen(s1)の返り値を変数に保存して条件式にその変数を使う方が動作は早くなるでしょう。

int len = strlen(s1);