C言語の基本|文字と文字列の違い

1文字はchar型、文字列はchar型配列。保存の仕組みを知れば、C言語の文字操作がすっきり見えてきます。

C言語では、文字と文字列を明確に区別して扱います。どちらも画面上では文字として表示されるため、学び始めたばかりのころは同じようなものに見えるかもしれません。

しかし、内部の仕組みは異なります。

  • 文字はchar型の変数へ1文字だけ保存する
  • 文字列はchar型の配列へ複数の文字を順番に保存する
  • 文字列の最後には終わりを示すナル文字が必要になる
  • 文字の表示には%c、文字列の表示には%sを使う

特にC言語には、独立した文字列型がありません。複数の文字をchar型配列へ並べ、最後にナル文字を置くことで文字列を表現します。

この違いを理解すると、printfによる表示、scanfによる入力、配列の操作、文字列関数、ポインタなど、この先の学習が進めやすくなります。

ここでは、文字と文字列の書き方、保存方法、ナル文字の役割、書式指定子の違い、文字列から1文字を取り出す方法を順番に解説します。

文字とは

C言語における文字とは、1つだけの文字を表すデータです。文字を保存するときはchar型の変数を使用します。

char grade = 'A';
char number = '7';
char symbol = '#';

文字定数は、シングルクォーテーションで囲みます。

変数保存する値内容
grade'A'アルファベットのA
number'7'数字として表示される7
symbol'#'記号の#

次の宣言では、変数gradeにAという1文字を保存しています。

char grade = 'A';

char型の変数は、1つの文字を保存する箱として考えると分かりやすくなります。

文字の7と整数の7は違う

次の2つは、見た目が似ていますが、異なるデータです。

char number = '7';
int value = 7;

numberに保存されているのは7という文字です。valueに保存されているのは計算に使う整数の7です。

記述種類主な用途
'7'文字表示や文字判定
7整数加算や乗算などの計算

文字の7をそのまま整数値7として計算に利用するものではありません。文字と数値は、見た目ではなくデータの種類で区別しましょう。

文字列とは

文字列とは、複数の文字を順番に並べたデータです。C言語では、文字列をchar型の配列で表します。

char word[] = "CODE";

文字列リテラルは、ダブルクォーテーションで囲みます。

文字列CODEは、配列の中へ次のように保存されます。

配列要素保存される文字
word[0]'C'
word[1]'O'
word[2]'D'
word[3]'E'
word[4]'\0'

画面に見える文字は4文字ですが、配列には最後のナル文字を含めて5要素が必要です。

図1:char型変数とchar型配列の違い

この図から分かること

char型変数には、1つの文字を保存します。一方、char型配列には複数の文字が要素ごとに保存され、最後にはナル文字が置かれます。

文字と文字列は、画面上では似たものに見えても、使用する変数やメモリ上の構造が異なります。

文字と文字列を表で比較する

比較項目文字文字列
意味1つの文字複数文字の並び
主な型char型char型の配列
宣言例char ch = 'A';char str[] = "ABC";
囲み方シングルクォーテーションダブルクォーテーション
表示方法%c%s
メモリ上の構造1文字分文字の並びと'\0'
要素の指定変数名配列名[添字]

特に覚えておきたいのが、次の違いです。

'A'

これはAという文字です。

"A"

こちらはAという文字列です。

"A"は表示上は1文字ですが、内部にはAとナル文字が入っています。

記述種類内部の内容
'A'文字Aという1文字
"A"文字列A、'\0'

文字列の最後にあるナル文字

C言語の文字列には、終わりを示すナル文字が必要です。

'\0'

ナル文字は、文字列の終端を示す特別な文字です。画面には表示されません。

たとえば、次の文字列を考えてみましょう。

char text[] = "CAT";

配列の内部は次のようになります。

'C' → 'A' → 'T' → '\0'

printfで%sを使って表示すると、配列の先頭から文字が順番に読み取られます。

'C'を読む
'A'を読む
'T'を読む
'\0'を見つける
文字列の読み取りを終了する

ナル文字があることで、printfは文字列の終わりを判断できます。

ナル文字は数字の0や文字の0とは違う

次の3つは、それぞれ意味が異なります。

記述意味
0整数値の0
'0'数字として表示される文字の0
'\0'文字列の終わりを表すナル文字

文字の'0'は画面に0と表示されます。ナル文字の'\0'は文字列の終端を示すため、通常は画面に表示されません。

この違いは、文字列を正しく扱うために大切です。

図2:ナル文字で文字列の終わりを判断する

この図から分かること

文字列CATは、C、A、Tだけで構成されているわけではありません。その後ろに、文字列の終了位置を示すナル文字が保存されます。

画面に見える文字数よりも、ナル文字の分だけ多く配列要素が必要になります。

文字と文字列で書式指定子が異なる

printfで文字を表示するときは%cを使います。

char mark = 'R';

printf("%c\n", mark);

文字列を表示するときは%sを使います。

char name[] = "Robot";

printf("%s\n", name);

書式指定子を整理すると、次のようになります。

データ変数例書式指定子
文字mark%c
文字列name%s

%cは1文字を表示します。

%sはchar型配列の先頭からナル文字が見つかるまで、文字を順番に表示します。

文字を%sで表示したり、文字列全体を%cで表示したりすると、データの形式が合わず、正しく動作しません。

文字と文字列を表示する

1文字の記号と装置名の文字列を表示するプログラム

ファイル名:10_11_1.c

#include <stdio.h>

int main(void)
{
    /* 1文字を保存するchar型変数 */
    char status = 'R';

    /* 文字列を保存するchar型配列 */
    char device_name[] = "Robot";

    printf("状態を表す文字:%c\n", status);
    printf("装置名の文字列:%s\n", device_name);

    return 0;
}
実行結果の例
状態を表す文字:R
装置名の文字列:Robot
char型変数へ1文字を保存する

次の宣言では、statusへRという1文字を保存しています。

char status = 'R';

statusはchar型の変数であり、配列ではありません。保存されるのはRという1文字だけです。

表示には%cを使用します。

printf("状態を表す文字:%c\n", status);
char型配列へ文字列を保存する

device_nameは、char型の配列です。

char device_name[] = "Robot";

配列要素の対応は次のようになります。

添字保存される文字
0'R'
1'o'
2'b'
3'o'
4't'
5'\0'

画面に表示されるのはRobotの5文字ですが、配列にはナル文字を含めた6要素が用意されます。

文字列全体を表示するため、%sを使用しています。

printf("装置名の文字列:%s\n", device_name);

%sはdevice_name[0]から読み始め、device_name[5]の'\0'を見つけたところで表示を終了します。

なぜ文字列はchar型配列なのか

C言語には、基本的な型として独立した文字列型が用意されていません。そのため、文字列を1文字ずつchar型配列へ保存します。

char name[] = "Robot";

これは、複数のchar型要素をひとまとまりにしたものです。

name[0]  name[1]  name[2]  name[3]  name[4]  name[5]
  'R'      'o'      'b'      'o'      't'      '\0'

文字列が配列として保存されるため、添字を使って各文字へアクセスできます。

printf("%c\n", name[0]);
printf("%c\n", name[1]);

この場合、Rとoが1文字ずつ表示されます。

文字列の一部分は文字になる

char型配列全体は文字列ですが、その中の要素を1つ指定するとchar型の文字になります。

char text[] = "GO";
記述データの種類内容
text文字列として扱えるchar型配列"GO"
text[0]char型の1要素'G'
text[1]char型の1要素'O'
text[2]char型の1要素'\0'

したがって、text全体の表示には%sを使います。

printf("%s\n", text);

text[0]やtext[1]の表示には%cを使います。

printf("%c\n", text[0]);
printf("%c\n", text[1]);

配列要素を変更すると文字列も変わる

文字列をchar型配列として用意すると、添字を使って各文字を変更できます。

char word[] = "cat";

word[0] = 'B';

word[0]のcがBへ変更されるため、文字列全体はBatになります。

添字変更前変更後
0'c''B'
1'a''a'
2't''t'
3'\0''\0'

ナル文字はそのまま残っているため、変更後も正しい文字列として表示できます。

図3:文字列全体と配列の各要素

この図から分かること

char型配列全体は文字列として扱えますが、添字を指定すると1つのchar型要素として扱えます。

配列要素を変更すると文字列の一部も変わります。文字列がchar型の配列だからこそ、1文字ずつ取り出したり書き換えたりできます。

文字列全体と各文字を表示する

文字列を全体表示し、各文字を個別に取り出すプログラム

ファイル名:10_11_2.c

#include <stdio.h>

int main(void)
{
    char message[] = "GO";

    printf("文字列全体:%s\n", message);
    printf("1文字目:%c\n", message[0]);
    printf("2文字目:%c\n", message[1]);

    return 0;
}
実行結果の例
文字列全体:GO
1文字目:G
2文字目:O
message全体を表示する処理

次の処理では、messageを文字列として表示しています。

printf("文字列全体:%s\n", message);

%sは、配列の先頭からナル文字までをまとめて表示します。

messageの内部は次のようになっています。

要素
message[0]'G'
message[1]'O'
message[2]'\0'
配列の各要素を表示する処理

次の処理では、messageの1要素を指定しています。

printf("1文字目:%c\n", message[0]);

message[0]はchar型の1文字なので、%cを使います。

printf("2文字目:%c\n", message[1]);

message[1]もchar型の1文字です。

同じmessageを使っていても、配列全体を指定するか、添字を付けて1要素を指定するかによって扱い方が変わります。

文字と文字列で起こりやすい間違い

間違いやすい点正しい考え方
'A'と"A"を同じものと考える'A'は文字、"A"は文字列
文字をダブルクォーテーションで囲む文字はシングルクォーテーションで囲む
文字列をシングルクォーテーションで囲む文字列はダブルクォーテーションで囲む
char型変数へ文字列を入れる文字列にはchar型配列を使う
文字を%sで表示する文字は%cで表示する
文字列を%cで表示する文字列は%sで表示する
ナル文字の存在を忘れる文字列の最後には'\0'が必要
配列全体と配列要素を混同する配列名は文字列、配列名[添字]は1文字

文字と文字列を区別する3つの視点

囲み方を確認する

'A'

シングルクォーテーションで囲まれているので文字です。

"ABC"

ダブルクォーテーションで囲まれているので文字列です。

宣言されている型と形を確認する

char ch;

char型変数なので1文字を保存します。

char str[10];

char型配列なので複数の文字を保存できます。

メモリ上の並びを考える

文字は1つのchar型変数に保存されます。

文字列は複数のchar型要素に分かれて保存され、最後にナル文字が置かれます。

この3つを意識すると、文字と文字列の違いを判断しやすくなります。文字列をchar型配列として理解できるようになると、添字を使った1文字ずつの参照や変更も自然に読み取れるようになります。