strcpyって使ってますか?
strcpyは文字列型データをコピーするために使用する関数です。
文字列はchar型の配列やchar型のポインタとして扱われます。
文字列型のデータを数値型のデータのように「=」記号を使って代入コピーしようとしても、配列の場合は代入できなかったり、ポインタの場合はアドレス先をコピーすることになるなど、意図通りにならないので注意が必要です。
この記事では、文字列のコピーについて
- 文字列の代入について
- strcpyの使い方について
- strcpyを使用する上での注意
- strcpy_sの使い方
など、よくやりがちなコピーの内容から、関数を使った文字列のコピーについてまで解説していきます。
今回は文字列のコピーについて、使い方をわかりやすく解説します!
文字列の代入について
文字列型のデータのコピーは数値型のデータのように「=」記号を使って代入コピーしようとしても、意図通りになりません。
配列の場合は代入することができません。ポインタの場合はアドレス先をコピーすることになります。
サンプルコードで確認していきましょう。
#include <stdio.h> int main(void) { char str1[16] = "Hello World!"; char str2[16]; /* 配列の代入は不可 str2 = str1; */ char *ptr1, *ptr2; ptr1 = str1; // char型ポインタにchr型配列のアドレスを代入 // 文字列のアドレスのコピー(浅いコピー) ptr2 = ptr1; printf("ptr2の文字列は: %s\n", ptr2); printf("ptr1のアドレス: %p, ptr2のアドレス: %p\n", ptr1, ptr2); str1[0] = 'h'; printf("ptr1の文字列は: %s\n", ptr1); printf("ptr2の文字列は: %s\n", ptr2); return 0; }
実行結果:
ptr2の文字列は: Hello World! ptr1のアドレス: 0x7ffce1776b50, ptr2のアドレス: 0x7ffce1776b50 ptr1の文字列は: hello World! ptr2の文字列は: hello World!
このサンプルコードでは、まずchar型配列「str1」を「=」記号を使って「str2」に代入しようとしています。
しかし、コンパイルエラーが発生するので コメントアウトしています。
次にchar型のポインタ「ptr1」に「str1」のアドレスを代入しています。
「ptr1」のアドレスを「=」記号を使って「ptr2」に代入しています。
結果「ptr1」と「ptr2」はアドレスが同じで、「ptr2」は「ptr1」の値と同じ値を表示しています。
この場合、「ptr1」は「str1」のアドレスですので、「str1」の最初の文字を「H」から「h」に変更すると「ptr1」の表示も変わりますが、「ptr2」の表示も変わりますので注意が必要です。
strcpyの使い方について
前述の理由で文字列のコピーには「=」記号を使った代入ではなく、strcpy関数を使用するのが一般的です。
strcpy関数はヘッダーファイル「string.h」をインクルードして使用します。strcpyの第1引数にはコピー先のアドレス、第2引数にはコピー元のアドレスを記入します。
それではサンプルコードで確認していきましょう。
#include <stdio.h> #include <string.h> int main(void) { char str1[16] = "Hello World!"; char str2[16]; // 文字列のコピー strcpy(str2, str1); printf("str2の文字列は: %s\n", str2); return 0; }
実行結果:
str2の文字列は: Hello World!
このサンプルコードでは文字型配列「str1」を「str2」へstrcpy関数を使ってコピーしています。
strcpyを使用する上での注意
strcpyで文字列をコピーする場合、バッファーオーバーフローについて注意する必要があります。
バッファオーバーフローのバッファとは、メモリ上に確保する領域のことを指します。
オーバーフローとは、バッファがあふれた状態を指します。メモリ上に確保されたバッファがあふれ、意図しない動作を引き起こすことがあります。
例えば、隣接したメモリのアドレスに不正に上書きするなどです。
C言語では変数で確保したバイト数以上に、値を代入することができてしまいます。
サンプルコードで確認しましょう。
#include <stdio.h> #include <string.h> int main(void) { char str1[16] = "Hello World!"; char str2[4]; // 文字列のコピー strcpy(str2, str1); printf("str2の文字列は: %s\n", str2); return 0; }
実行結果:
str2の文字列は: Hello World!
先ほどのサンプルコードと同じように、文字型配列「str1」を「str2」へstrcpy関数を使ってコピーしています。
ですが、str1のバイト数が16に対して、str2で確保したメモリのバイト数は4で足りていません。
C言語では確保したバイト数が足りなくてもそのまま処理してしまいます。
これが原因で意図しないメモリの書き込みが発生してしまうこともありますので、注意しましょう!
strcpy_sの使い方
Visual StudioのC++の環境でコンパイルする際には注意が必要です。
VisualC++ではstrcpy関数を使用するとコンパイルエラーが発生し、strcpy_s関数を使うようにメッセージが表示される場合があります。
strcpy_s関数を使う場合は、文字列で受け取るメモリ領域のサイズを指定する必要があります。
strcpy_sの第1引数にはコピー先のアドレス、第2引数にはコピー先のバッファサイズ、第3引数にはコピー元のアドレスを記入します。
strcpy_s(コピー先のアドレス, コピー先のバッファサイズ, コピー元のアドレス)
サンプルコードで確認しましょう。
#include <stdio.h> #include <string.h> int main(void) { char str1[16] = "Hello World!"; char str2[16]; // 文字列のコピー strcpy_s(str2, 16, str1); printf("str2の文字列は: %s\n", str2); system("pause"); // 出力表示のための一時停止 return 0; }
実行結果:
str2の文字列は: Hello World! 続行するには何かキーを押してください . . .
文字列の使い方総まとめ
この記事では紹介しきれなかった文字列のいろいろな使い方を次の記事にまとめているので、ぜひ確認してください!
まとめ
ここでは、文字列をコピーする方法について説明しました。
「=」記号を使った代入では意図通りにコピーすることができない場合があります。
strcpy関数を使って文字列をコピーすることができるように、この記事を何度も参考にして下さいね!