C言語基礎|9章のまとめ

ナル文字がつく瞬間、ただの配列が「文字列」になる。9章で“文字列の正体”をつかもう!

9章のまとめは「文字列を安全に扱う総仕上げ」

9章では、文字列は単なる文字の集まりではなく、ナル文字(値0)を終端の合図にした char 配列として扱う、というC言語らしい世界を学びました。

この章のゴールはシンプルで、

  • 文字列リテラルの内部(末尾にナル文字が付く)
  • 配列に文字列を格納するやり方(初期化、入力)
  • 文字列を走査する考え方(長さ、表示、検索、変換)
  • そして「関数に渡すときのルール」
    を、手で書けるレベルまで落とし込むことです。

9章で覚えた“文字列の核”を一望する

9章の重要ポイント早見表

テーマキーワード何が大事?つまずきポイント
ナル文字値0、終端文字列の終わりの目印終端が無いと文字列として扱えない
文字列リテラル"ABC" など末尾にナル文字が付く見た目の文字数と必要バイト数が違う
sizeof とリテラルsizeof("...")末尾ナル文字込みのサイズ途中に \0 があると表示の意味が変わる
記憶域期間静的記憶域期間プログラム開始〜終了まで生存いつ作られていつ消えるかの誤解
char配列文字列の格納先最初のナル文字までが文字列配列の要素数=文字列長ではない
初期化"ABC" や {'A',...}宣言時だけ特別に楽に書ける宣言後に s = "ABC" はできない
空文字列""中身0文字、終端だけ長さ0でも配列要素は最低1必要
走査先頭から '\0' まで長さ、表示、検索の基本'\0' を表示しない/止める
表示printf の %s'\0' 直前まで表示終端が無いと暴走の危険
入力scanf の %s配列名をそのまま渡す& を付けると事故りやすい
関数の受け渡し配列渡し実引数は配列名だけ要素数は普通不要(終端まで処理するから)

表の説明

  • 9章の内容は、全部「終端ナル文字」と「走査」で一本につながります。
  • 表示も入力も関数渡しも、ナル文字までをどう扱うかが核心です。

ナル文字と文字列リテラルの内部を図で再確認

文字列リテラルは末尾にナル文字が付く

  • "ABC" は「3文字」ではなく 4文字分 の領域を使います。
  • "" でも、終端が必要なので 1文字分 を使います。

sizeof("...") が返す値は「末尾ナル文字込み」

sizeof と“見た目”のズレ

リテラル見た目中身(概念)sizeof のイメージ
"123"3文字1 2 3 04
"AB\tC"4文字っぽいA B (タブ) C 05
"abc\0def"7文字っぽいa b c 0 d e f 08

表の説明

  • \t は2文字の書き方でも実体は1文字(タブ文字)です。
  • \0 は途中に置けます。表示上はそこで終わったように扱われますが、領域としては後ろも存在します。
  • sizeof は「領域の大きさ」を返すので、途中の \0 があっても後ろの分も含みます。

文字列リテラルの性質:寿命とまとめ方は別問題

文字列リテラルの2つの性質

性質どういうこと?なぜ重要?
静的記憶域期間プログラム開始から終了まで生存関数内に書いても消えない
同一綴りの扱いは処理系依存同じ "ABCD" を1つにまとめるかは環境次第メモリ節約の有無は保証されない

表の説明

  • "ABCD" は関数に入るたびに作られるものではなく、基本はずっと生きています。
  • ただし「同じものを共有するか」は、コンパイラの最適化などで変わるので、そこに依存した設計はしません。

文字列の格納先は char 配列、終端は最初のナル文字

char配列に格納された文字列

図の説明

  • 配列の要素数が6でも、文字列の長さが3とは限りません。
  • 最初に出てきた 0(ナル文字)までを文字列とみなします。
  • 末尾側の未使用領域は、初期化していないと不定値のままです。

文字配列の初期化:宣言時だけ特別に楽

文字配列の初期化の書き方

書き方特徴
文字を並べるchar str[] = {'A','B','C','\0'};仕組みが分かりやすい
文字列で書くchar str[] = "ABC";基本はこれ、簡潔

表の説明

  • どちらも結果は同じで、末尾にナル文字が入ります。
  • 宣言後に str = "ABC" のような代入はできません(配列は代入できない)ので、更新したいときは1文字ずつ代入するか、別の手段を使います。

文字列の走査ができれば、表示・長さ・検索は作れる

文字列の基本操作は「先頭から1文字ずつ、ナル文字まで進む」です。

走査の基本形(イメージ)

i=0から開始
s[i] が 0 ではない間:
  文字を処理
  i++
0 に出会ったら終了

説明

  • 走査は「止まる条件」が明確で、それがナル文字です。
  • 長さは「何回進んだか」。表示は「進みながら出力する」。検索は「一致するまで探す」です。

printf と scanf:%s は“ナル文字まで”

Table 5 %s の意味(表示と入力)

関数変換指定何をする?重要注意
printf%sナル文字の直前まで表示終端が無い配列を渡すと危険
scanf%s空白までの文字列を読み込み配列に格納格納先に & を付けない

表の説明

  • printf の %s は「文字列」を要求します。終端が無いと止まれません。
  • scanf の %s は配列名をそのまま渡します。配列名は先頭要素への参照として扱われるためです。

サンプルプログラム

9章まとめとして、ここでは 9章の要点を1本で復習できる 形のプログラムです。

目的:

  • 文字列を読み込む(scanf)
  • 長さを数える(走査)
  • putchar で1文字ずつ表示(走査)
  • 数字文字の合計を出す('0' を引く)

プロジェクト名:chap9-12-1 ソースファイル名:chap9-12-1.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

#include <stdio.h>

// 文字列の長さ(ナル文字の直前まで)を返す
int str_length(const char s[])
{
    int len = 0;
    while (s[len])
        len++;
    return len;
}

// 文字列を1文字ずつ表示(改行しない)
void put_string(const char s[])
{
    int i = 0;
    while (s[i])
        putchar(s[i++]);
}

int main(void)
{
    char s[128];
    int sum = 0;

    printf("短い文字列を入力してね:");
    scanf("%127s", s);

    // 数字文字の合計を計算
    for (int i = 0; s[i]; i++) {
        if (s[i] >= '0' && s[i] <= '9')
            sum += s[i] - '0';
    }

    printf("入力したのは:");
    put_string(s);
    putchar('\n');

    printf("文字数は%dです。\n", str_length(s));
    printf("数字の合計は%dです。\n", sum);

    return 0;
}

実行例

短い文字列を入力してね:FukuOka79
入力したのは:FukuOka79
文字数は9です。
数字の合計は16です。

命令の書式と「何をする命令か」

sizeof の書式と役割

  • 書式
    sizeof 式
    sizeof(型)
  • 何をする?
    その式や型が占有するバイト数を返します。文字列リテラルでは末尾ナル文字込みのサイズになります。

printf の書式と役割

  • 書式
    int printf(const char *format, ...);
  • 何をする?
    書式付き表示。%s はナル文字までを文字列として表示します。最小フィールド幅や精度で桁数や切り詰めも指定できます。

scanf の書式と役割

  • 書式
    int scanf(const char *format, ...);
  • 何をする?
    入力を読み取って変数へ格納。%s は配列へ文字列を格納します。配列に & を付けないのがポイントです。
    さらに安全のため %127s のように最大長を付けると安心です。

putchar の書式と役割

  • 書式
    int putchar(int c);
  • 何をする?
    1文字出力します。文字列を自力で表示したいときに使います。

for / while の書式と役割

  • for
    for (初期化; 継続条件; 更新) 文;
    回数や範囲が見えている繰り返しに向きます。
  • while
    while (条件式) 文;
    ナル文字まで走査するような「終端条件で止まる」処理にぴったりです。

関数で受け取る文字列:要素数が不要な理由

文字列を引数にする基本ルール

立場書き方意味
呼び出し側str_length(str);配列名だけ渡す
呼び出される側int str_length(const char s[])配列として受け取る(実体は同じ領域)

表の説明

  • 文字列はナル文字で終端が分かるので、通常は要素数を別に渡す必要がありません。
  • 変更しないなら const を付けると「書き換えない意図」が伝わって安全です。