ログイン
kid's world

文字列型?

文字列型?

では,いよいよ今回の本題「文字列」について解説を始めよう。

PascalやPerlなど,文字列型の存在するプログラミング言語は多くあるが,C言語には実は「文字列型」という型はない。だからといって,文字列が扱えないというわけではない。ではどのようにしたら文字列を扱うことができるのだろうか。

char型へのポインタ

文字列は「文字の連なり」である。したがって,苦肉の策(もしくは力技)のように思えるかもしれないが,メモリ上に文字を順番に連ねていき,その先頭アドレスを使って「文字列型」を扱ったふりをするのだ。

具体的には,1文字はchar型で表されるから,char型の連続したメモリを確保し,その先頭アドレスを指し示す「char型へのポインタで」文字列を扱う(Fig. 1)。malloc関数を使って動的にメモリを確保してもよいし,次のように配列を使っても同じことができる。

char s[10];
s[0] = 'A';
s[1] = 'B';
s[2] = 'C';
s[3] = '\0';

Fig. 1: 文字列は「char *」で扱う

/c/string-fig1.png

このような配列を作ったとき,「s」は,先頭の'A'を指すchar型へのポインタ(char *)となっていることはもうわかると思うが,C言語ではこれを文字列の代わりとして扱うのだ。

最後の要素に'\0'というエスケープ文字を代入しているが,これはヌル文字といい,その具体的な値は0である。'0'という文字ではないことに注意したい。C言語で扱う文字列では,文字列の最後に,'\0'をつけるという決まりになっている。

ヌル文字は,「ここは文字列の終わりです」という意味として使われるのだ。もしこの記号がなければ,文字列の終端がどこかわからずに困ることになる。具体的にどう困るかは,そのうちわかってくるだろう。

ともかく,C言語において文字列は,「char *」で扱われ,文字列の終わりは'\0'であるということが,基本中の基本である。

文字列定数

たとえば,

printf("ABC");

というように,プログラム上に"ABC"という文字列があったとしよう。このような文が出てきても,おそらく「"ABC"」はいったい何なのかということを考えもせずに使ってきたことと思う。

ダブルクォート「"」で文字列を囲んだものは文字列定数と呼ばれており,なんとこれは「char型の配列」である。「"ABC"」と単純に書くと,'A','B','C','\0'という4つの要素を持ったchar型の配列が知らず知らずのうちに作られ,その先頭へのポインタが返されている,と考えてもよいだろう。

ここでちょっと頭をひねってみよう。「文字列リテラルはchar型へのポインタである」と考えれば,今まで,

printf("ABC");

というように文字列定数を渡されていたprintf関数は,実はchar型へのポインタを渡されていて,その先頭から'\0'までの文字を順番に表示していたということになる。この事実を実験によって確かめてみよう。

List 7では,char型へのポインタsを宣言し,"ABC"を代入している。"ABC"というのは,char型へのポインタなのだから,この代入は正しい。そしてこのポインタsをprintf関数の引数に指定している。

List 7: printf関数へポインタを渡す(その1)

#include <stdio.h>

main()
{
  char *s;
  
  s = "ABC";
  printf(s);
}

さらに,List 8のプログラムでは,わざと配列を使って同じようなことを実現している。char型の配列を宣言するのと同時に,その配列の初期化を行い,その先頭ポインタ(配列名)をprintf関数に渡している。

List 8: printf関数へポインタを渡す(その2)

#include <stdio.h>

main()
{
  char s[4] = {'A', 'B', 'C', '\0'};

  printf(s);
}

配列の初期化の方法はここで初めて出てきたので,簡単に説明しよう。

初期値を大カッコでくくって先頭からコンマで区切って指定すれば,配列の要素を任意の値で初期化できる。なお,「s[4]」の部分を「s[]」と省略してもよく,その場合は初期値として指定した値の数(この場合は4)だけの要素を持つ配列ができあがる。

なお,いちいち,

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

と書くのはめんどうなので,特別に,

char s[] = "ABC";

という書き方が許されている。

ここで,

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

などという代入は行えないことに注意したい。なぜなら配列はポインタとは違い,代入することはできないからだ。

どちらの例も実行すると画面上に「ABC」と表示される。

どのようにメモリは使われていたか

筆者もそうなのだが,理解が浅いときや理解に不安を感じるとき,納得いくまでいろいろ実験してみたくなるものである。

そこで,そういった筆者を含めた疑い深いプログラマのために,C言語のプログラムの中で「"ABC"」という文字列定数が出てきたときに実際にどの部分のメモリが使われているのかを実験によって確認したい。

やり方は簡単だ。List 7を少し変更すればよい。たとえばList 9のように書くことができる。こうすれば,1行目に「"ABC"」の先頭アドレス,2行目にchar型へのポインタsのアドレスが表示される。

List 9: メモリの使われ方を探る

#include <stdio.h>

main()
{
  char *s;
  
  s = "ABC";
  printf("%X\n%X\n",s,&s);
}

筆者のPCではFig. 2のような実行結果となった。したがって,Fig. 3のようなメモリの使われ方をされていたということが予想できる。

Fig. 2: List 9の実行結果

/c/string-fig2.png

Fig. 3: このようにメモリが使われていた

/c/string-fig3.png

これでなんとなく,C言語における文字列の使い方がわかってきただろうか。


文字列の操作」へ進む

広告


©Toshio Koide 1996-2007.

目次

リンクについて

リンクは御自由にどうぞ。

メール

mail.gif

広告