/*01*/ #include <stdio.h>
/*02*/
/*03*/ main()
/*04*/ {
/*05*/ char str[32] = "Hello, world.\n";
/*06*/
/*07*/ printf("str = %s\n", str);
/*08*/
/*09*/ return 0;
/*10*/ }
文字列と言っても、1つの変数に何文字もを入れることは出来ません。1つの文字変数には1つの文字しか入らないのです。このことは先に書いたとおり「文字変数には文字コードが入っているにすぎない」事を考えれば納得できると思います。ですから、文字列を扱うためには文字型の配列を用意し、それがあたかも文字列であるかのように扱います。ちょうど、原稿用紙の1マスには1文字しか書かないのといっしょです。
というわけで32個の要素をもつ char 型の配列 str を作りました。次に代入するのですがその前に注意することがあります。C言語では配列のの中でそこが文字列の終わりであることを
char x[32]; と宣言し、配列分いっぱいに文字列を代入した場合、 | H | e | l | ... | d | . | \n | \0 | ------------------------------------------------------- ...| 528 | 529 | 530 | ... | 556 | 557 | 558 | 559 |... ------------------------------------------------------- |x[0] |x[1] |x[2] | ... |x[28]|x[29]|x[30]|x[31]| 「\0」は、これで1文字なのです。このほかにも「\n」などの制御文字は、 それで1文字として扱います。
では、代入(初期化)しましょう。ですが、実はこの代入がクセモノなのです。まず、最も簡単な方法は list-4.2.1 にあるとおり宣言と同時に初期化する場合です。ですが list-4.2.1 を見て「アレ?」と思いませんか?本当なら「\0」を書かないといけませんよね。ここでちょっと、1文字の時と比べてみましょう。
char ch = 'a'; char str[32] = "Hello, world.\n";
初期化と同時に宣言しなかった場合はかなり面倒になります。というのは、基本的に配列1つづつに、個別に代入していかなければならないからです。
char str[32]; str[0] = 'H'; str[1] = 'e'; str[2] = 'l'; str[3] = 'l'; str[4] = 'o'; : : str[12] = 'd'; str[13] = '.'; str[14] = '\n'; str[15] = '\0';
ですが、これではあまりに不便なので、標準ライブラリ関数
/* ヘッダーファイル string.h をインクルードします。 */ strcpy(str, "Hello, world.\n");
strcpy(str1, str2);
さてさて、strcpy の例でお気づきになったでしょうか?
strcopy(str1, str2);
この関数では、第2引数から渡された文字列を、第1引数で指定されたアドレスを先頭とする領域に代入していきます。それに対し第2引数の方は、第2引数で指定されたアドレスから「\0」までを文字列として処理します。
要するに、C言語では指定されたアドレス(ポインタ)から「\0」までを文字列として扱うことになっているのです。
文字列の理解を深めるために list-4.2.2 を見てください。
/*01*/ #include <stdio.h>
/*02*/ #include <string.h>
/*03*/
/*04*/ main()
/*05*/ {
/*06*/ char str1[32] = "Hello, Programing.";
/*07*/ char str2[32] = "World.";
/*08*/ char *st = &str1[7];
/*09*/
/*10*/ printf("strcpy 前\n");
/*11*/ printf("str1 = %s\n", str1);
/*12*/
/*13*/ strcpy(st, str2);
/*14*/
/*15*/ printf("strcpy 後\n");
/*16*/ printf("str1 = %s\n", str1);
/*17*/
/*18*/ st = &str1[14];
/*19*/ printf("str1 の後ろ = %s\n", st);
/*20*/
/*21*/ return 0;
/*22*/ }
まず、char 型ポインタ変数 st には str1 の「P」にあたる部分、つまり str[7] を指しておきます。そして、strcpy で st のアドレス(つまり str[7])以降を文字列 str2 に置き換えます。これで、次の printf 文では「Hellow, World.」と表示されるはずです。なお、「Hellow, World.ming.」とならないのは「World」の直後に「\0」が自動的に代入されるからです。ですが、その後ろには「Programing.」の残骸「ing.(及び '\0')」が残るので、「'i'」にあたる部分のアドレスを文字列のはじめとして指定すれば、そこを文字列として扱うことができます。.
| l | d | . | \0 | i | n | g | . | \0 | ------------------------------------------------------------- ...| 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 |... ------------------------------------------------------------- |x[10]|x[11]|x[12]|x[13]|x[14]|x[15]|x[16]|x[17]|x[18]|
このことから、指定されたアドレスから「\0」までを文字列として扱うことを再確認してください。このことは、他の関数を使う上ではもちろんのこと、C言語で文字列を扱う上での大原則ですので、きちんと理解しておきましょう。
さて、printf での文字列の扱いです。printf で文字列を表示するための変換文字は「%s」です。そして、第2引数以降で指定されたアドレス(普通は文字列の先頭アドレス)から「\0」までを1つの文字列として表示します。
ちなみに、漢字などの2バイト(全角)文字は char 型配列のうち2バイト分、つまり2つ分を使って文字列として扱います。ですから、漢字1文字を扱いたい場合でも、最低「2バイト + ’\0’の分」で、3バイト以上の配列が必要になります(char str[3] = "漢"; のように)。
プログラムの先頭で、大文字と小文字が存在する文字列
char str[32] = "HeLlo, woRLd.";
ポインタ p を使って str を先頭から '\0' まで読み取って行きます。その際、p の指す要素が小文字であるならばそこを大文字に変えます。