
C言語基礎|配列の文字列とポインタの文字列の違い
“文字列”は同じ見た目でも、配列は箱、ポインタは住所。だから代入の可否が変わる!
前節で、配列で作った文字列も、ポインタで扱う文字列も、printf の %s で同じように表示できることを確認しました。
でも実はこの2つ、中身の正体がまったく別なんです。
配列の文字列は「文字が入った箱(固定された領域)」、ポインタの文字列は「どこかにある文字列の先頭を指す住所札(付け替え可能)」というイメージ。
この違いが分かると、なぜ配列に文字列を代入できないのか、なぜポインタなら代入できるのかがスッと理解できますよ。

まずは全体像:何が違うの?
配列の文字列とポインタの文字列の比較
| 項目 | 配列による文字列 | ポインタによる文字列 |
|---|---|---|
| 宣言例 | char s[] = "ABC"; | char *p = "123"; |
| 変数の正体 | 文字を格納する配列(箱そのもの) | 先頭文字のアドレスを持つポインタ(住所札) |
| 代入(付け替え) | s = "DEF" は不可(エラー) | p = "456" は可(OK) |
| 文字の変更 | s[0] = 'X' は可能 | p[0] = 'X' は原則危険(後述) |
| sizeof の結果 | 配列全体のバイト数 | ポインタのバイト数 |
| 主な用途 | 書き換える前提の文字列 | 切り替えたい・参照したい文字列 |
この表の見方
- 「配列」は中身(文字)を抱えている
- 「ポインタ」は中身ではなく「場所」を抱えている
ここが分かれば勝ちです。
サンプルプログラム
例1:配列の文字列は代入できない(コンパイルエラー)
#include <stdio.h>
int main(void)
{
char msg[] = "START";
printf("最初の表示: %s\n", msg);
msg = "GO"; // エラー:配列には代入できない
printf("変更後の表示: %s\n", msg);
return 0;
}なぜエラー?
配列 msg は「固定された箱」です。箱そのものを別の箱に付け替えるような代入 msg = "GO" はできません。
例2:ポインタの文字列は代入できる(OK)
#include <stdio.h>
int main(void)
{
char *p = "ON";
printf("現在の状態: %s\n", p);
p = "OFF"; // OK:ポインタが指す先を付け替えるだけ
printf("切り替え後: %s\n", p);
return 0;
}ここで起きていること
文字列をコピーしているわけではなく、p が指す先(住所)を切り替えているだけです。
図で理解:配列は「箱」、ポインタは「住所札」
配列の文字列(箱そのもの)

ポインタの文字列(住所札)

図の説明
- Fig 1 は「文字列の実体が msg の中にある」ことを示しています
- Fig 2 は「p の中身はアドレスで、指す先を変更できる」ことを示しています
重要ポイント:配列名がポインタっぽく見える理由
C言語では多くの場面で、配列名は先頭要素へのポインタとして扱われます。
でもこれは「配列がポインタになる」のではなく、式として評価されるときにそう見えるだけです。
配列名が“先頭要素へのポインタっぽく”なる場面
| 表現 | 意味(ざっくり) |
|---|---|
| msg | &msg[0] と同じように扱われる場面が多い |
| &msg[0] | 先頭要素へのポインタ |
| msg = ... | これは不可(代入の左側が配列だから) |
ここが混乱の根っこ
- msg は「ポインタのように扱われる」ことがある
- でも msg 自体は「配列」で、代入で付け替えはできない
文字列リテラルは“消えない”ことが多い(静的な領域)
ポインタで文字列リテラルを切り替えると、前の文字列リテラルはどうなるの?という話も大事です。
ポインタを切り替えると「参照されないリテラル」が出る

図の説明
- リテラルは「不要になったら自動で破棄」されるイメージではない
- ポインタが指さなくなっても、リテラル自体は残ることが多い
- だから「コピーしていない」ことがよりハッキリします
登場する命令(関数)の書式と役割
printf
- 書式:printf(書式文字列, 引数1, 引数2, ...);
- 何をする命令?:文字を画面に表示する
- よく使う指定
・%s:char へのポインタを受け取り、'\0' までを文字列として表示する
・\n:改行
(補足)ポインタ文字列は書き換えに注意
ポインタ p が文字列リテラルを指しているとき、次は危ないです。
char *p = "ON";
p[0] = 'X'; // 多くの環境で危険
「読み取り専用の可能性がある領域」を触ることになるからです。
読み取り専用として扱うなら、次の形が安心です。
おすすめの宣言
| 意図 | 宣言 |
|---|---|
| リテラルを読むだけ | const char *p = "ON"; |
| 自分で書き換える | char s[] = "ON"; |
演習問題
問題11-1
次の代入を行うと、表示はどうなるか確認し、理由を説明せよ。
p = "MELON" + 2;
解答例プログラム
#include <stdio.h>
int main(void)
{
char *p = "APPLE";
printf("最初: %s\n", p);
p = "MELON" + 2;
printf("変更後: %s\n", p);
return 0;
}実行結果(例)
最初: APPLE
変更後: LON解説(やさしく)
- "MELON" は M E L O N \0 の並び
- "MELON" + 2 は、先頭から2文字進んだ 'L' を指す
- %s は指された位置から \0 まで表示する
だから LON になる、という流れです。
途中から指すイメージ

