文字列をコピーするプログラムを作ってみましょう。
まず、枠組みを作成します。
<sample program 084-00>
#include <stdio.h> #define MAX_STRING 10 int main(void) { char str1[MAX_STRING]; char str2[MAX_STRING]; scanf("%s", str1); /* ここにプログラムを追加する */ printf("str2 = %s\n", str2); return 0; } |
<実行結果>
ABC ←scanfの入力 str2 = ABC 続行するには何かキーを押してください・・・
コピーというのは、ある文字列を別の配列にコピーする、ということです。
非常に間違いやすい考え方から説明しますと、
str2 = str1; |
こういう書き方は出来ません。
コンパイルの段階で、
error C3863: 配列型 'char [10]' を割り当てることはできません。
というエラーが出ます。
これは一度、配列の説明の際にも書いた内容です。
「文字列」は配列ですから、配列の時に勉強したことが役に立ちます。
それでは、実際に作成してみてください。
解答例です。
<sample program 084-01>
#include <stdio.h> #define MAX_STRING 10 int main(void) { char str1[MAX_STRING]; char str2[MAX_STRING]; int i; scanf("%s", str1); for (i = 0; i < MAX_STRING; i++) { str2[i] = str1[i]; } printf("str2 = %s\n", str2); return 0; } |
<実行結果>
ABCDE ←scanfの入力 str2 = ABCDE 続行するには何かキーを押してください・・・
配列str1の中身を1文字ずつ、str2へコピーしました。
これできちんと動作するのですが、9文字入っていても、2文字しか入っていなくても配列の中身を全部コピーしますよね。
scanfで入力した文字列の最後にはヌル文字が入っていますからヌル文字が入っている箇所までをコピーした方が効率が良さそうです。
すでにその形(ヌル文字までコピー)で作っている人は解答例を見てください。
これから作る人は、頑張って考えましょう。
表示は上手くいってますか?
このように変な文字が表示されている場合、ヌル文字がどうなっているかよく考えてください。
解答例です。
<sample program 084-02>
#include <stdio.h> #define MAX_STRING 10 int main(void) { char str1[MAX_STRING]; char str2[MAX_STRING]; int i; scanf("%s", str1); for (i = 0; str1[i] != '\0'; i++) { str2[i] = str1[i]; } str2[i] = '\0'; printf("str2 = %s\n", str2); return 0; } |
<実行結果>
ABCDE ←scanfの入力 str2 = ABCDE 続行するには何かキーを押してください・・・
もし、赤字の
str2[i] = '\0'; |
が無ければ、ヌル文字がstr2に入らず、たまたまヌル文字(ゼロ)がある箇所まで文字を表示してしまいます。
イメージするのが難しいと思う方に、図で説明します。
scanf で str1 に文字列 "AB" を入力した直後の配列
str1 0 1 2 3 4 5 6 7 8 9 +−+−+−+−+−+−+−+−+−+−+ | A| B|\0|不|不|不|不|不|不|不| +−+−+−+−+−+−+−+−+−+−+ ※不:不定 str2 0 1 2 3 4 5 6 7 8 9 +−+−+−+−+−+−+−+−+−+−+ |不|不|不|不|不|不|不|不|不|不| +−+−+−+−+−+−+−+−+−+−+
for文に入ってからの動き
1.iが0の時、str1[0]はヌル文字ではないためfor文の中に入る
2.str2[0] = str1[0];を実行した後の配列
str1 0 1 2 3 4 5 6 7 8 9 +−+−+−+−+−+−+−+−+−+−+ | A| B|\0|不|不|不|不|不|不|不| +−+−+−+−+−+−+−+−+−+−+ ↓ str2 0 1 2 3 4 5 6 7 8 9 +−+−+−+−+−+−+−+−+−+−+ | A|不|不|不|不|不|不|不|不|不| +−+−+−+−+−+−+−+−+−+−+
3.iがインクリメントされ1になる
4.str1[1]はヌル文字ではないためfor文の中に入る
5.str2[1] = str1[1];を実行した後の配列
str1 0 1 2 3 4 5 6 7 8 9 +−+−+−+−+−+−+−+−+−+−+ | A| B|\0|不|不|不|不|不|不|不| +−+−+−+−+−+−+−+−+−+−+ ↓ str2 0 1 2 3 4 5 6 7 8 9 +−+−+−+−+−+−+−+−+−+−+ | A| B|不|不|不|不|不|不|不|不| +−+−+−+−+−+−+−+−+−+−+
6.iがインクリメントされ2になる
7.str1[2]はヌル文字のため、繰り返し条件が成り立たずfor文が終わる
この時点(iが2の時点)ではstr2にはヌル文字が入っていない
このような状態のため、
str2[i] = '\0'; |
が必要なのです。
もちろん、作り方によっては上手くループの中でヌル文字までコピーする方法もあります。
<sample program 084-03>
#include <stdio.h> #define MAX_STRING 10 int main(void) { char str1[MAX_STRING]; char str2[MAX_STRING]; int i; scanf("%s", str1); for (i = 0; ; i++) { str2[i] = str1[i]; if (str1[i] == '\0') { break; } } printf("str2 = %s\n", str2); return 0; } |
<実行結果>
ABCDE ←scanfの入力 str2 = ABCDE 続行するには何かキーを押してください・・・
繰り返し条件を省略し、break文でfor文から抜け出す仕組みに変えました。
配列の要素(文字)をコピーした後で、「コピーした文字はヌル文字だったか」を調べるため、きちんとヌル文字までコピーされています。
他にも色々や作り方があると思いますが、何度も説明しているようにヌル文字を意識してプログラムを考えてください。
次回は文字列の連結をやります。