C言語のきほん|char配列に文字列を設定する方法

char配列に文字列を入れる方法が分かると、C言語の文字列操作がぐっと身近になる。
初期化の書き方と終端文字の意味を、ここでしっかり押さえよう。

C言語で文字列を扱うときに、まず必ず理解しておきたいのが char配列にどうやって文字列を入れるか という点です。
前の内容で、C言語には独立した文字列型がなく、文字列は char型の配列で表すことを学びました。
ここでは、その一歩先として、char配列に文字列を設定する具体的な方法 を整理していきます。

いちばん基本的な書き方は、文字列リテラルを使った初期化です。
でも実際には、それ以外にもいくつか方法があります。

  • 文字列リテラルで初期化する
  • 文字を1つずつ並べて初期化する
  • 配列サイズを明示して初期化する
  • 後から1文字ずつ代入する
  • 標準ライブラリ関数を使ってコピーする

どの方法も同じように見えるかもしれませんが、ナル文字 \0 をどう扱うか配列サイズをどう決めるかあとから代入できるかどうか といった点で違いがあります。
ここをあいまいにしてしまうと、表示が崩れたり、思わぬバグの原因になったりします。

特にC言語では、文字列の終わりを示す \0 がとても重要です。
見た目には "ABC" のように3文字しかなくても、内部では A、B、C、\0 という並びになっています。
つまり、文字列を安全に扱うには、見えている文字数だけでなく、終端文字の分まで意識する必要がある ということです。

この項では、char配列に文字列を設定するいくつかの方法を、シンプルな例に置き換えながら丁寧に見ていきます。
さらに後半では、複数の文字列を2次元配列で扱う考え方にも触れていきます。
1つの文字列だけでなく、複数の単語や名前をまとめて扱う場面では、ここもとても大切な考え方になります。

char配列に文字列を入れるとはどういうことか

まず、char配列に文字列を設定するとはどういうことなのかを整理しておきましょう。

たとえば、次のようなコードがあります。

char str[] = "ABC";

このとき、str には "ABC" という見た目のデータが入っているように見えます。
でも、実際の中身は次のようになっています。

要素格納される値
str[0]'A'
str[1]'B'
str[2]'C'
str[3]'\0'

つまり、文字列を入れるというのは、文字を順番に並べて、最後に \0 を置くこと です。

この感覚がとても大切です。
C言語では文字列は特別な箱ではなく、あくまで char型の要素が並んだ配列 として扱われます。

まず押さえたい基本

char配列に文字列を設定するときは、次の3点を特に意識しておくと理解しやすいです。

ポイント内容
文字列は char型配列で表す1文字ずつ並んだデータとして扱う
末尾に \0 が必要文字列の終わりを示すため
サイズに注意する表示文字数 + 1 が必要になる

たとえば 3文字の ABC を保存したいなら、必要な大きさは 3 ではなく 4 です。
この +1 を忘れないことがとても大事です。

文字列リテラルで初期化する方法

いちばん基本的で、最もよく使う方法です。

char str[] = "ABC";

この書き方では、要素数を自分で書かなくても、コンパイラが自動的に必要なサイズを決めてくれます。
ABC は3文字ですが、最後に \0 が付くので、配列サイズは4になります。

この方法の特徴

項目内容
書きやすさとても書きやすい
\0 の扱い自動で追加される
サイズ指定省略できる
おすすめ度とても高い

文字列を初期値として入れるだけなら、この方法が最も自然で分かりやすいです。

間違えやすい例

char str[3] = "ABC";

これは一見よさそうに見えますが、サイズが3しかありません。
ABC を文字列として扱うには A、B、C に加えて \0 が必要なので、4が必要です。

このようにすると、文字列の終わりを示す \0 が入らない形になってしまい、安全に文字列として扱えなくなります。

文字ごとに初期化する方法

次は、文字を1つずつ並べて初期化する方法です。

char str[] = {'A', 'B', 'C', '\0'};

この方法では、文字列リテラルではなく、各要素を明示的に指定しています。
そのため、\0 も自分で書く必要があります。

この方法の特徴

項目内容
書き方1文字ずつ並べる
\0 の扱い自分で書く必要がある
見通し配列の実体が分かりやすい
注意点\0 を忘れやすい

配列の中身を1文字ずつ意識したいときには、とても分かりやすい方法です。
ただし、\0 を忘れると文字列として正しく扱えなくなるので注意が必要です。

配列サイズを明示して初期化する方法

次のように、サイズを指定して初期化することもできます。

char str[10] = "ABC";

この場合、配列全体のサイズは10です。
そこに A、B、C、\0 が入り、残りの要素は 0 で埋められます。

この方法の特徴

項目内容
配列サイズ自分で決められる
余裕を持たせるできる
\0 の扱い自動で追加される
用途後で別の短い文字列を入れる余地を作れる

たとえば後で別の内容に入れ替える可能性があるときは、このように少し大きめに配列を確保しておくことがあります。

たとえば str[10] に "ABC" を入れると、内部イメージは次のようになります。

要素
str[0]'A'
str[1]'B'
str[2]'C'
str[3]'\0'
str[4] ~ str[9]'\0'

後から1文字ずつ代入する方法

配列を先に用意して、後から文字を順番に入れることもできます。

char str[4];
str[0] = 'A';
str[1] = 'B';
str[2] = 'C';
str[3] = '\0';

この方法も、最終的にはきちんと文字列になります。
ただしここでも、最後に \0 を忘れないこと がとても重要です。

この方法の特徴

項目内容
柔軟さ高い
1文字ずつ制御できる
\0 の扱い手動で必要
注意点書き忘れやすい

この方法は、プログラムの途中で文字を組み立てるような場面で役立ちます。
ただ、単純に固定の文字列を入れるだけなら、文字列リテラルで初期化する方法のほうが簡単です。

配列には後から文字列リテラルを直接代入できない

ここはとても大事なルールです。

次のような書き方はできません。

char str[10];
str = "ABC";

これは誤りです。
配列は、宣言後にまとめて = で別の文字列リテラルを代入することはできません。

この点は、普通の変数と少し感覚が違うところです。
たとえば int型変数なら、あとから別の値を代入できます。
でも、配列はそういう形では扱えません。

後から文字列を入れたいときは strcpy を使う

配列に後から文字列を入れたいときは、標準ライブラリ関数の strcpy を使います。

#include <string.h>

char str[10];
strcpy(str, "ABC");

この書き方なら、ABC と \0 が str にコピーされます。

strcpy を使うときの注意

注意点内容
ヘッダが必要string.h を使う
配列サイズが必要コピー先に十分な大きさが必要
\0 もコピーされるその分も含めて考える

たとえば "ABC" をコピーするなら、最低でも4バイト必要です。
コピー先の配列が小さすぎると危険なので、必ずサイズを意識しましょう。

サンプルプログラムで確認してみよう

サンプルプログラム

ファイル名:10_12_1.c

#include <stdio.h>
#include <string.h>

int main(void)
{
    /* 文字列リテラルで初期化する */
    char city1[] = "Osaka";

    /* 後から文字列をコピーする */
    char city2[10];
    strcpy(city2, "Kyoto");

    printf("最初の都市名は %s です。\n", city1);
    printf("次の都市名は %s です。\n", city2);

    return 0;
}

実行結果例

最初の都市名は Osaka です。
次の都市名は Kyoto です。

このサンプルで分かること

このプログラムでは、2つの方法で文字列を設定しています。

1つ目の方法

char city1[] = "Osaka";

これは宣言と同時に文字列リテラルで初期化する方法です。
サイズは自動で決まり、O、s、a、k、a、\0 が入ります。

2つ目の方法

char city2[10];
strcpy(city2, "Kyoto");

こちらは、いったん大きさ10の配列を用意してから、strcpy で文字列をコピーしています。
後から内容を設定したいときはこちらの考え方が必要になります。

char配列に文字列を設定する方法

配列サイズを決めるときの考え方

char配列に文字列を設定するときは、何文字入るかだけでなく、\0 の分も考えないといけません。
ここをきちんと整理しておくとミスが減ります。

入れたい文字列見えている文字数必要な最小サイズ
A12
ABC34
Hello56
Kyoto56

この表から分かるように、必要なサイズは 文字数 + 1 です。

2次元配列で複数の文字列を扱う

文字列が1つだけなら1次元の char配列で十分です。
でも、複数の文字列をまとめて管理したいときは、2次元配列を使います。

たとえば次のようなコードです。

char fruits[3][7] = {"Apple", "Banana", "Cherry"};

これは、3つの文字列をまとめて持つための配列です。
1行に1つの文字列が入るイメージです。

ただし、このままでは少し注意が必要です。
Apple は 5文字 + \0 で 6、Banana は 6文字 + \0 で 7、Cherry も 6文字 + \0 で 7 です。
そのため、列数は少なくとも 7 必要です。

2次元配列の考え方

行番号入る文字列
0Apple
1Banana
2Cherry

つまり、

  • 行の数 = 文字列の個数
  • 列の数 = 1つの文字列を入れるための最大サイズ

という考え方になります。

行数は省略できるが、列数は必要

多次元配列では、初期化時に先頭の要素数だけは省略できます。

char words[][7] = {"Apple", "Banana", "Cherry"};

この場合、3行であることは初期値の個数から自動的に決まります。
でも、列数である 7 は省略できません。

これは、コンパイラが1行あたり何文字分の領域を確保するかを知る必要があるからです。

1次元配列と2次元配列の違い

ここで、1つの文字列と複数の文字列の扱いを整理しておきます。

扱うもの使う配列
1つの文字列char str[]
複数の文字列char words[][列数]

たとえば、

char name[] = "Sora";

は1つの文字列です。

一方で、

char names[3][10] = {"Sora", "Yui", "Kenta"};

は3つの文字列をまとめて持っています。

よくある間違い

char配列に文字列を設定するときは、次のようなミスが起こりやすいです。

\0 を忘れる

文字を1つずつ代入するときに、最後の \0 を書き忘れると、文字列として正しく扱えません。

サイズが足りない

ABC を入れるのに 3 で足りると思ってしまうのは、よくあるミスです。
実際には \0 の分も必要なので 4 が必要です。

配列にあとから = で代入しようとする

これはできません。
後から入れるなら strcpy を使います。

学習のコツ

この内容は、丸暗記よりも「なぜそうなるか」を意識すると理解しやすくなります。

意識したいポイントは次の3つです。

コツ内容
中身を配列として見る文字列は文字の並びである
\0 を忘れない終わりの印が必要
サイズは文字数 + 1見えている文字数だけでは足りない

この3つを自然に考えられるようになると、char配列への文字列設定だけでなく、その先の文字列処理もかなり理解しやすくなります。

もう1つの短い例

最後に、文字を1つずつ代入して文字列を作る小さな例も見ておきましょう。

ファイル名:10_12_2.c

#include <stdio.h>

int main(void)
{
    char word[4];

    /* 1文字ずつ文字列を作る */
    word[0] = 'C';
    word[1] = 'a';
    word[2] = 't';
    word[3] = '\0';

    printf("作成した単語は %s です。\n", word);

    return 0;
}

実行結果例

作成した単語は Cat です。

このプログラムを見ると、1文字ずつ入れたとしても、最後に \0 があれば文字列として表示できることが分かります。
逆に言うと、\0 がないと、見た目がそれらしくても文字列として完成していない、ということです。