WisdomSoft - for your serial experiences.

6.4 文字列ポインタ

文字配列と文字列へのポインタについて解説します。性質的に、リテラル文字列を指すポインタから、リテラル文字列を変更してはいけません。リテラル文字列から読み込んだ文字列を編集する場合は配列に複製する必要があります。

6.4.1 リテラル文字列へのポインタ

リテラル文字列を配列初期化子に指定することで、配列に文字列を格納することができました。そこで、ある疑問が浮上します。初期化子以外の式でリテラル文字列を指定した場合、このリテラル文字列はどのような型として評価されているのでしょう。実は、リテラル文字列はその文字列へのポインタを返しています。

例えば printf("Kitty on your lap") という文は、printf() 関数に char * 型の値を引数として渡していると考えることができます。では、この文字列はどこに格納されているのでしょうか。

リテラル文字列や数値などの定数は、全てコンパイル時に固定値としてバイナリ化され、最終的に実行ファイルにデータが格納されます。プログラムの実行時にこのデータが定数値としてメモリに読み込まれるようになっています。具体的に、定数をどのように保存し、実行時にどのように読み込むかはコンパイラやシステムに依存します。

このことを考えると、リテラル文字列はプログラムを実行している時にはすでにメモリに格納されているため、配列初期化子を使って異なる配列にコピーをするというのは、文字単位の編集などを意図しない限り意味のない行為です。目的に応じて、リテラルを指すポインタを使うのか、配列に複製するかを選択する必要があります。

char chStr[] = "Kitty on your lap";

上記の文はリテラル文字列を新しい配列 chStr にコピーすることになります。リテラル文字列から生成した配列を編集する場合に有効ですが、単に文字列を指す変数を用意したいだけであれば、リテラル文字列を配列に複製する必要はありません。

char *chpStr = "Kitty on your lap";

これは、配列初期化子にリテラル文字列を指定する文とは大きな違いがあります。chStr[] = "..." は文字列を格納するだけの十分な配列が割り当てられ、これに指定したリテラル文字列をコピーしますが、*chpStr = "Kitty on your lap" の場合は、実行ファイルからメモリに読み込まれたリテラル文字列へのアドレスを代入しているにすぎません。

コード1
#include <stdio.h>

int main() {
	char *chpStr = "Kitty on your lap";
	printf("%s\n" , chpStr);
	return 0;
}
実行結果
コード1 実行結果

コード1では、ポインタ chpStr にリテラル文字列 "Kitty on your lap" へのアドレスを代入しています。結果は予想通り "Kitty on your lap" という文字列を表示するだけです。このとき、ポインタからリテラル文字列の内容を変えてはいけません。内容の変更を試みた場合の結果は不定とされています。