Nodachisoft Nodachi Sword Icon
  
@あまじ✎ 2018年6月22日に更新

第2章05 文字列変数の宣言、初期化と表示

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

この記事でやること

前回はプロジェクト「0030_moji」を新しく作って、char型の変数の宣言や初期化の方法、足し算を計算して、ASCIIコード表をベースに変換した結果を表示するプログラムを書きました。

今回は、char 型を使って文章(文字列)の初期化と表示の方法をお話しようと思います。

新しい Mojiretsu プログラム

ではでは 文字列を取り扱うサンプルプログラムを作成してみましょう。

プロジェクト「0040_mojiretsu」を新しく用意し、 プロジェクトに空の「Mojiretsu.c」を追加し、下のソースコードをコピペして動かしてみましょう。

 
Mojirestu.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);
}

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

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

まずそうなランチ

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

4行目~6行目で文字列を扱う変数の宣言と初期化(代入)を行っています。

それぞれ宣言と初期化の方法をわけて書いています。いろんな宣言と初期化の方法があるということでご紹介したかったので。

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

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

  • char player[]; … 文字列の変数の宣言
  • player = "ぷらんく"; … 文字列の代入

のように2つのコードに分解することができます

char 変数名[]; で以降、変数名に文字列を代入することができます。

ここには日本語も入れることができます。また、記号 [ ]配列を意味しています。

配列は簡単にいうと「char 型変数をたくさん並べて、たくさんの文字(日本語含む)を保存できるようにしている」 となんとなく理解してもらえればと思います。

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

配列についてのお話はまた後ほどお話するとして、こんな風に文字列を初期化することができるということを理解してもらえればとおもいます。 5行目ですが、こちらも変数の宣言と初期化を同時にやっています。

char* 変数名;

で以降、「変数名」という変数に文字列を代入することができます。 6行目も文字列 "Oyaji" を変数 waiterName に入れる、という処理をしています。

char 変数名[使う文字のサイズ] = {1文字 , 1文字 , 1文字 … 1文字, '\0' };

という書き方をしており、ソースコードには書きづらいですが、こんな書き方もある、という例として挙げています。

'\0'NULL終端文字と呼ばれる制御文字です。 使い方は後ほどお話しますね。

あと、この書き方だと日本語は書けません。理由は前回お話しましたが、日本語は1文字のサイズ(バイト)ではなく、2文字以上のサイズをとるからです。

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

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

 
Mojiretsu.c
 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)が理解する命令に近い形に変換すると細かな違いが見えてきます。

|[[info | 細かい話なので前置き ]] | ここは細かい話で、私がお勉強&メモとして書いている項目なので、ふーん…程度に読んでいただければ。あとポインタとか定数の知識が必要なので、今読んでも意味不明と思われるかもしれません。このパートは飛ばしていただいてまったく問題ありませんので、後々このシリーズを読んだ後にもういちど来てもらえばなんとなく意味がわかるように書いていきたいです。お役に立てたら嬉しいのですが。

文字列の宣言と初期化の方法(で内部でやってること)

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

あとがき

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

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

ページの更新履歴

更新日 更新内容
更新なし
イチからゲーム作りで覚えるC言語
第2章04 char型変数を使って1文字表示して計算する : PREV
NEXT : 第2章06 いろんな書式指定子 :
 
 
送信しました!

コメント、ありがとうございます。

なんかエラーでした

ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。

Twitter:@NodachiSoft_jp
お名前:
 
連絡先:
 
メッセージ:
 
戻る
内容の確認!

以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください

お名前:
 
連絡先:
 
メッセージ:
 
Roboto からの操作ではないという確認のため確認キーを入れてください。
確認キー=95
戻る
 / 
送信確認へ
コメント欄
コメント送信確認へ

関連ありそうな記事(5件)です!

ゲーム等で使えるつなぎ目のないループするテクスチャ画像の作り方

#ツール#ゲームプログラミング✎ 2021-01-24
ゲームなどで使えるループ画像、パターンテクスチャのツール、手動での作り方をまとめ
広告領域
追従 広告領域
目次
第2章05 文字列変数の宣言、初期化と表示
第2章05 文字列変数の宣言、初期化と表示
この記事でやること
この記事でやること
新しい Mojiretsu プログラム
新しい Mojiretsu プログラム
文字列を扱う変数の宣言と初期化(いろんな方法があるよ)
文字列を扱う変数の宣言と初期化(いろんな方法があるよ)
変数に設定した、文字列の表示
変数に設定した、文字列の表示
3種類の文字列配列の初期化の違いについて(オマケ)
3種類の文字列配列の初期化の違いについて(オマケ)
あとがき
あとがき
非常に参考になったサイトさまや、参考文献など
非常に参考になったサイトさまや、参考文献など
ページの更新履歴
ページの更新履歴
Nodachisoft © 2020