
C言語入門|文字列は先頭アドレスで渡す
ここまでで、私たちは C言語における文字列の正体をかなり深く理解してきました。
- 文字列の実体は char 配列であること
- 文字列の終わりは \0 で決まること
- \0 以降のメモリは「文字列ではない」こと
これらを理解したことで、
「なぜ C言語の文字列は扱いが独特なのか」
その理由が、だんだん見えてきたのではないでしょうか。
そしてここで、もう1つ重要な 業界ルールの続き を知る必要があります。

C言語の文字列に関する業界ルール
C言語の世界では、文字列を扱う際に次のルールが暗黙の前提として共有されています。
| 条文 | 内容 |
|---|---|
| 第1条 | 先頭要素から順に1文字ずつ文字コードを格納して文字列を表す。 |
| 第2条 | 最後の文字の直後に文字コード0を置き、以降は無視する。 |
| 第3条 | 文字列を関数などに渡す場合は、先頭文字のアドレスだけを渡す。 |
| 暗黙条 | 配列を複製する方法は問わない。 |
今回の主役は、この 第3条 です。
なぜ「先頭アドレスだけ」でいいのか
たとえば、500文字からなる長い文字列があるとします。
先頭アドレスは仮に 8000 番地としましょう。
この文字列を printf で表示したい場合、
本当に 500文字分すべての情報を渡す必要があるでしょうか?
答えは NO です。
printf は、
- 渡されたアドレスから読み始め
- 次の文字、さらに次の文字と順にたどり
- \0 に到達したら処理を終える
という動きをします。
つまり、
先頭文字のアドレスさえ渡せば
あとは printf が勝手に最後まで読んでくれる
これが、第3条の考え方です。
printf と文字列の受け渡しの正体
私たちはこれまで、何気なく次のようなコードを書いてきました。
char str[1024] = "hello";
printf("%s", str);一見すると、「str に入っている文字列そのもの」を
printf に渡しているように見えます。
しかし、配列変数名が式の中に書かれると
それは、
先頭要素のアドレスに化ける
のでした。
つまりこのコードは、実際には次の意味になります。
printf("%s", &str[0]);最初から最後まで、
文字列の先頭アドレスしか渡していなかった のです。
業界ルールが支えている仕組み
ここで重要なのは、
- 第1条:順番に文字が並んでいる。
- 第2条:\0 で終わる。
というルールがあるからこそ、
- 第3条:先頭アドレスだけ渡せばよい
という仕組みが成立している、という点です。
もし \0 が存在しなければ、
printf は「どこまで表示すればいいのか」分からなくなってしまいます。
C言語における文字列管理の考え方
この文化をひとことで表すと、こうなります。
長い文字列でも、
先頭アドレスだけを管理し、やり取りに使う
(末尾は \0 によって自動的に分かる)
これが、C言語における文字列管理の基本思想です。
「文字列」と「文字列を指すポインタ」の混同
ここで、C言語特有の ややこしさ が登場します。
次のコードを見てください。
char str[1024] = "hello";
char* p = str;
printf("%s, %s\n", str, p);このコードでは、str も p も、
どちらも同じように hello を表示します。
- str は char 配列で、文字情報そのものを持っている
- p は char* 型で、文字列の先頭アドレスを持っているだけ
にもかかわらず、
どちらも「文字列」として扱われてしまうのです。
なぜこんな呼び方がされるのか
本来の意味での「文字列」とは、
メモリ空間に並んだ文字情報そのもの
です。
しかし C言語の世界では、
文字列は先頭アドレスで管理する
という文化があまりにも定着しているため、
- 文字列本体
- 文字列の先頭アドレス
この両方をまとめて
文字列と呼ぶことが多い のです。
これが、C言語が「紛らわしい」と言われる大きな理由の1つでもあります。
ここまで理解できたら一段上
この節の内容が自然に理解できるようになったなら、
あなたはもう、
- ポインタに振り回される初心者
- 文字列が怖いCプログラマ
ではありません。
文字列を
- メモリ
- アドレス
- \0
という視点で捉えられる、
C言語らしい思考 が身についてきています。
次のステップへ
次は、
- 文字列を受け取る関数の書き方
- char* 引数の意味
- 書き換え可能な文字列とそうでない文字列
といった話に進んでいきます。
「文字列は先頭アドレスで渡す」
この考え方が、これから何度も登場することになるでしょう。
