第2章05 文字列変数の宣言、初期化と表示@イチからゲーム作りで覚えるC言語

イチからゲーム作りで覚えるC言語
連載ページ一覧へ
2章06 いろんな書式指定子
NEXT : 2章06 いろんな書式指定子
2章04 char型変数を使って1文字表示して計算する : PREV

この記事でやること

前回はプロジェクト「0030_moji」を新しく作って、char型の変数の宣言や初期化の方法、足し算を計算して、ASCIIコード表をベースに変換した結果を表示するプログラムを書きました。
今回は、char 型を使って文章(文字列)の初期化と表示の方法をお話しようと思います。

この記事はゆる~くC言語でゲームを作りながらプログラミングを学ぶための連載記事です。シリーズものですので記事の一覧はこちらを参照してくださいね。

新しい Mojiretsu プログラム

ではでは 文字列を取り扱うサンプルプログラムを作成してみましょう。
プロジェクト「0040_mojiretsu」を新しく用意し、プロジェクトに空の「Mojiretsu.c」を追加し、下のソースコードをコピペして動かしてみましょう。

#include <stdio.h>
int main( void )
{
 char player[] = "ぷらんく";
 char* lunchA = "小麦スープ";
 char waiterName[6] = { 'O', 'y', 'a', 'j', 'i','\0'};
 printf("%s:お金がないのでお昼は格安 A ランチにします\n", player );
 printf("%s:ほらよっ、A ランチの「%s」だぜ!\n"
   , waiterName, lunchA);
 printf("%s:(うわぁ、まずそうです・・。)\n", player);
}

実行すると、下のような結果になったと思います。

ぷらんく:お金がないのでお昼は格安 A ランチにします
Oyaji:ほらよっ、A ランチの「小麦スープ」だぜ!
ぷらんく:(うわぁ、まずそうです・・。)

まずそうなランチ

文字列を扱う変数の宣言と初期化(いろんな方法があるよ)

4行目~6行目で文字列を扱う変数の宣言と初期化(代入)を行っています。
それぞれ宣言と初期化の方法をわけて書いています。いろんな宣言と初期化の方法があるということでご紹介したかったので。

 char player[] = "ぷらんく";
 char* lunchA = "小麦スープ";
 char waiterName[6] = { 'O', 'y', 'a', 'j', 'i', '\0'};

4行目ですが、変数の宣言と初期化を同時に行っています。

  1. char player[]; … 文字列の変数の宣言
  2. player = “ぷらんく”; … 文字列の代入

のように2つのコードに分解することができます
char 変数名[]; で以降、変数名に文字列を代入することができます。
ここには日本語も入れることができます。また、記号 [ ]配列を意味しています。
配列は簡単にいうと「char 型変数をたくさん並べて、たくさんの文字(日本語含む)を保存できるようにしている」となんとなく理解してもらえればと思います。

char型の配列

char型の配列で作られた変数「hensuu」の例

配列についてのお話はまた後ほどお話するとして、こんな風に文字列を初期化することができるということを理解してもらえればとおもいます。

5行目ですが、こちらも変数の宣言と初期化を同時にやっています。
char* 変数名; で以降、「変数名」という変数に文字列を代入することができます。

6行目も文字列”Oyaji” を変数 waiterName に入れる、という処理をしています。
char 変数名[使う文字のサイズ] = {1文字 , 1文字 , 1文字 … 1文字, ‘\0’ };
という書き方をしており、ソースコードには書きづらいですが、こんな書き方もある、という例として挙げています。
‘\0’NULL終端文字と呼ばれる制御文字です。使い方は後ほどお話しますね。
あと、この書き方だと日本語は書けません。理由は前回お話しましたが、日本語は1文字のサイズ(バイト)ではなく、2文字以上のサイズをとるからです。

変数に設定した、文字列の表示

7行目から変数に設定した文字列を表示するプログラムとなっています。

 printf("%s:お金がないのでお昼は格安 A ランチにします\n", player );
 printf("%s:ほらよっ、A ランチの「%s」だぜ!\n"
   , waiterName, lunchA);
 printf("%s:(うわぁ、まずそうです・・。)\n", player);

すでにprintf のフォーマット識別子については、int型とchar型(一文字表示)を読んでいただいていれば、なんとなく読めるのではないでしょうか。
%s文字列を表示するために使う識別子です。player の変数や、lunchA の変数に設定した文字列を表示できているかと思います。
%s は英語のスペルの String(文字列)の頭文字とみると覚えやすいと思います。

8行目と9行目は1つの printf 関数呼び出しの命令を2行にわけて書いています。
関数も横に長いときは行を分けて見やすくしたいと思いますよね。
今回は、一つ目の引数(文字列)と2つ目以降の引数(変数名を記載)で別々の行に分割しました。
関数名を書いてる途中や、変数名などの途中に改行やスペースを入れることはできませんが、それ以外の場所には見やすくするためにいくら書いても大丈夫です。

NULL終端文字の使われ方と、使い方

ASCIIコード表でみると、数値の 0 (制御コードNULL) は NULL終端文字と呼ばれ、文字列の最後は、自動的にNULL終端文字が入るようになっています。
NULL終端文字と文字列の関係は、後の配列についてのページでもお話しますので、今は理解できなくても大丈夫です;
char name[] = “usagi”;
であれば、char型の ‘u’、’s’、’a’、’g’、’i’ の次にNULL終端文字が自動的に入っていることになります。

文字列「usagi」とNULL終端文字の例

文字列「usagi」とNULL終端文字の例

printf関数などで文字列を表示するときは、この NULL終端文字 を printf 関数のプログラムがチェックして、NULL終端文字が出現するまで、順番に一文字づつ表示しているという仕組みになっています。
NULL終端文字は意図的に 「\0」 で書くことができます。

たとえば、
char name[] = “かめ\0へび”;
と文字列を定義して表示すると、「かめ」だけが表示されます。
これは、 \0 で文字列が終わっていると printf が判断するためです。

ソースコードの6行目の
char 変数名[使う文字のサイズ] = {1文字 , 1文字 , 1文字 … 1文字, ‘\0’ };
だと、文字の束に一文字づつ代入しているという書き方になるので、
自動的に ‘\0’ が代入されないため、手動で ‘\0’ を書いてあげるという意味になります。

もし’\0’(NULL終端文字)を最後に書かないで「char 変数名[使う文字のサイズ] = {1文字 , 1文字 , 1文字 … 1文字};」で定義した文字列を printf で表示しようとした場合、どのような文字が表示されるかは保証されません。もし実行して文字の表示が延々とされて終わらない場合は、Ctrl + c などでプログラムを中断しましょう。

3種類の文字列配列の初期化の違いについて(オマケ)

このページの中で、3種類の変数の宣言と初期化の方法をご紹介しました。どれも同じ結果が得られるように見えますが、Visual Studio 2017 でビルドして動かしてみた時、実際にはそれぞれPCが内部で行っている処理はそれぞれ異なったものになります。

今回のソースコードをアセンブラという、より機械(CPU)が理解する命令に近い形に変換すると細かな違いが見えてきます。
※ここは細かい話で、書いている人がお勉強&メモとして書いている項目なので、ふーん…程度に読んでいただければ。あとポインタとか定数の知識が必要なので、今読んでも意味不明と思われるかもしれません。このパートは飛ばしていただいてまったく問題ありませんので、後々このシリーズを読んだ後にもういちど来てもらえばなんとなく意味がわかるように書いていきたいですね。

文字列の宣言と初期化の方法(で内部でやってること)
書き方処理の方法
char player[]
 = “ぷらんく”;
あらかじめメモリ上に”ぷらんく”という文字列定数の領域を用意し、そこから、4バイトづつ player ポインタ位置に読み取っていく処理を順次行って初期化します。(文字列をコピーする処理をしています
char* lunchA
 = “小麦スープ”;
あらかじめメモリ上に”小麦スープ”という文字列定数の領域を確保し、そこへのポインタ(アドレス)を設定しています。(文字列のコピーは発生せず、main関数のスタック・セグメントにもポインタのための領域しか確保されません。)
char waiterName[6]
= { ‘O’, ‘y’, ‘a’, ‘j’, ‘i’, ‘\0’};
あらかじめメモリ上に”Oyaji” という文字列は確保せず、waiterName へのポインタを作成したら、ポインタ先の領域に対して 1 バイトづつ文字をポインタ位置をずらしながら、コピーする処理をしています。

あとがき

今回はここまで。お疲れさまでした。

イチからゲーム作りで覚えるC言語
連載ページ一覧へ
2章06 いろんな書式指定子
NEXT : 2章06 いろんな書式指定子
2章04 char型変数を使って1文字表示して計算する : PREV

非常に参考になったサイトさまや、参考文献など

  • https://

ページの更新履歴

更新日更新内容
更新なし