Rubyではとても手軽にできた、「文字列同士の大小比較」や 「改行文字の切り取り(chomp)」も、C言語ではとてもややこしい。
C言語で文字列の操作をするときには、C言語の文字列がどんな構造になって いるかをつねに考えていないとできないと言っても過言ではない。 先週学習したことを繰り返そう。
Cの文字列は、char型(8ビット)数値の配列である
文字列の終わりを意味するマークとして最後の配列要素には
\0(文字コード0の文字) が入る
これを終始意識していないとすぐに理解の限界がやってくる。 復習しよう。
char s[] = "Hello";
というCの文があったとき、コンピュータ内部では次のような配列が 作られる。
s | |||||
|---|---|---|---|---|---|
| s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | 
| 'H' | 'e' | 'l' | 'l' | 'o' | '\0' | 
| 72 | 101 | 108 | 108 | 111 | 0 | 
C言語では文字をシングルクォート(')で括ったものは、その文字の
      文字コードを意味する。
      例: 'A' == Aの文字コード == 65
ある文字の文字コードを知りたいときはEmacsで知りたい文字の上に カーソルを合わせて C-x = をタイプする。たとえば、 Aの文字に合わせて、C-x = すると、
Char: A (0101, 65, 0x41) point=1 of 46 (0%) column 0
と出る。括弧内の数値(0101,65,0x41)が文字コードで、それぞれ 8進数、10進数、16進数表記となっている。
C言語プログラムで文字列 "Hello" が出てきたら
'\0' が付いているんだぜ
 ということを瞬時に思い浮かべるようにする。
Ruby言語では文字列の大小関係の比較は数値と同様 ==  <=
>=を使えば良かった。C言語では文字列専用の比較関数である
strcmp を使う。
strcmp - 文字列の大小比較
      プログラムの先頭に
#include <string.h>
を追加した上で以下のような書式で利用する。
strcmp(文字列その1, 文字列その2)
strcmp関数は、文字列その1と
      文字列その2 の大小(辞書順並び)を調べて、その結果を
      int型の数値で返す。
返す。イメージとしては、文字コードを使って
「文字列その1」-「文字列その2」
という引き算を計算した結果を返しているのだと 考えて良い。
実際にstrcmp を使って文字列の比較をしてみよう。
【入力した文字が y か n かで処理を切り替える】
  :
  :
char line[3];	/* y か n なら3文字で足りるだろう(改行と\0を忘れずに) */
  :
printf("続けますか?(y/n): ");
fgets(line, sizeof line, stdin);  /* 実際の読みこみ y \n \0 か n \n \0 */
if (0 == strcmp(line, "y\n")) {
  /* y と答えた場合の処理をここに書く */
} else {
  /* n と答えた場合の処理をここに書く */
}
  :
  :
      文字列の長さは文字列の先頭から '\0' が現れるまでの
文字数を数えれば良い。これを行なうのが strlen 関数である。
これも
#include <string.h>
が必要である。
strlen - 文字列の長さを返す
      文字列を持つchar型配列を渡して以下のように利用する。
strlen(文字列)
与えた「文字列」の長さを整数で返す。
strlenは、文字列のおしりの位置を探す場合にも使える。
たとえば、fgetsを使って名前を読み込んだとしよう。
char s[10];  /* 10バイト確保 */
  :
printf("あなたの名前は?: ");
fgets(s, sizeof s, stdin);
  :
↓
"taro" と入力しリターンを押すと、char型配列には以下のようなデータが 入る。
s | |||||||||
|---|---|---|---|---|---|---|---|---|---|
| s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] | s[9] | 
't' | 'a' | 'r' | 'o' | '\n' | 
  '\0' | ??? | ??? | ??? | ??? | 
116 | 97 | 114 | 111 | 10 | 
  0 | ??? | ??? | ??? | ??? | 
ここでRubyの達人は思うだろう。
最後の改行文字、要らねー
このような場合は、
文字列の最後の文字が改行文字か調べて、もしそうなら削る
という処理を書けば良い。このときにstrlenが役に立つ。
"taro\n" という文字列の長さは5である。文字列の最後の
'\n' の位置(添字)は4である。つまり、
strlenで帰って来た結果から1を引くと必ず 文字列の最後の文字の位置(添字)になる
という規則を利用すると、Rubyのchomp に相当する
処理は以下のように書ける。
char s[10];
printf("あなたの名前は?: ");
fgets(s, sizeof s, stdin);
if ('\n' == s[strlen(s)-1]) {
  s[strlen(s)-1] = '\0';
}
文字列 s は配列 であるから、その個別の要素を
指定するときはRubyと同様 s[添字] とする。その添字に
文字列の長さ-1 を指定すると文字列の最後の文字 を
指定することになる。
strlen(s) → 文字列sの長さ strlen(s)-1 → 文字列sの長さ-1 s[x] → 文字列sのx番目の配列要素 ↓ ∴ s[strlen(s)-1] は 文字列の最後の文字を指し示す配列要素
そして、本来改行文字 '\n' が入っていた場所に
文字列の終端を表す '\0'(文字コード0の文字) を
代入することで、めでたく末尾の改行文字を削除できる。