🔤 文字列
🎯 文字列を1文字ずつ走査する型を身につけ、数える・削る・逆順にするが書ける
文字列処理も、配列と同じで「型」で覚えます。土台になるのは、このfor文です。
for (int i = 0; s[i] != '\0'; i++) {
// s[i] に対する処理
}条件が i < n ではなく s[i] != '\0' になっているのがポイントです。長さを知らなくても、終わりの印に出会うまで進めばよい。これがCの文字列の走査の基本形です。
配列のときは i < n と要素数で止めました。文字列で要素数がなくても止まれるのは、終わりの印(ヌル文字)が配列の中に書かれているからです。裏を返せば、印のない配列を回すと止まりません。この形が安全に動くのは「渡された文字列が正しく終端されている」という前提があってこそです。
定石1: 数える
#include <stdio.h>
int count_char(const char s[], char target)
{
int cnt = 0;
for (int i = 0; s[i] != '\0'; i++) {
if (s[i] == target) {
cnt++;
}
}
return cnt;
}
int main(void)
{
printf("%d\n", count_char("banana", 'a')); // 3
return 0;
}特定の文字を数える、条件に合う文字を数える——if の中身を変えるだけで応用が利きます。
定石2: 入力の改行を取り除く
fgets で読み込むと、末尾に改行 '\n' が付いてきます。これを消すのが定番の処理です。
#include <stdio.h>
#include <string.h>
int main(void)
{
char line[64];
if (fgets(line, sizeof(line), stdin) != NULL) {
size_t len = strlen(line);
if (len > 0 && line[len - 1] == '\n') {
line[len - 1] = '\0'; // 改行の位置を終端に置き換える
}
printf("[%s]\n", line);
}
return 0;
}'\0' を上書きするだけで文字列が短くなる、というのがCらしい発想です。長さの情報がどこにも無いので、印の位置がすべてを決めます。len > 0 の確認を入れているのは、空文字列のときに line[-1] を踏まないためです。
定石3: 逆順にする
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[] = "stressed";
int n = (int)strlen(s);
for (int i = 0; i < n / 2; i++) {
char t = s[i];
s[i] = s[n - 1 - i];
s[n - 1 - i] = t;
}
printf("%s\n", s); // desserts
return 0;
}両端から1つずつ入れ替え、真ん中まで進んだら終わり。i < n にすると2回入れ替えて元に戻ってしまうので、n / 2 が正解です。ここでも '\0' は動かさないことに注目してください。終端の位置は変わらないので、文字列としての長さもそのままです。
定石4: 状態を覚えながら走査する
空白で区切られた単語の数を数えたいとき、空白の個数を数えるだけでは正しくありません。空白が連続していたり、先頭や末尾に空白があったりするからです。そこで「いま単語の中にいるか」を int in_word のような変数で覚えておき、空白でない文字が空白の次に現れた回数を数えます。走査しながら状態を持つ、という発想は文字列処理でくり返し登場します。1文字だけを見て判断できないときは、たいてい状態変数の出番だと考えてください。
罠・注意
i < strlen(s) と書くと、毎回先頭から数え直すので遅くなります。長さは変数に入れておきましょう。'\0' を置くだけで済みますが、長くするときは配列の大きさが足りているか必ず確認します。const char s[] と書けば「読むだけの文字列」を宣言できます。書き換えない関数には付けておくと安全です。i を勝手に進めると、'\0' を飛び越えて配列の外まで走り続けることがあります。1文字ずつ確実に進めるのが基本です。まとめ: 走査は s[i] != '\0'、短くするのは '\0' の書き込み、入れ替えは両端から。配列で覚えた型が、そのまま文字列でも生きます。
文字列の終わりを示すために置かれる、値0の特殊な文字'\0'のこと。これが無いと、どこまでが文字列かコンピュータが判断できなくなる。strlenなどの関数は、この'\0'を目印にして文字列の長さを数えている。
「初期化・条件・更新」の3つを1行にまとめて書ける繰り返し構文のこと。回数があらかじめ決まっている繰り返しにとくに向いている。繰り返す回数があらかじめはっきりしている場面で、とくに書きやすい構文。
もっと先へ:ポインタ・メモリ・ファイル入出力・セキュアコーディングを含む全26トラックと、段位検定・模試のフルセットは完全版に収録しています。