ポインターが定数データを指していない限り (文字列リテラルが定数データである場合を除き)、ポインターを配列として使用することに本質的に問題はありません。意味的には正しくありませんが、メモリ保護のない昔は、pmessage[0] = 'n';
実際には予測できない結果をもたらしていました (たとえば、プログラム内の同じリテラルのすべての出現に影響を与えます)。最新のオペレーティング システムでは、メモリ保護が設定されているため、これは発生しませんでした。文字列リテラルおよびその他の定数は、実行可能ファイルのいわゆる読み取り専用セクションに配置され、プロセスを作成するために実行可能ファイルがメモリにロードされると、読み取り専用セクションを含むメモリ ページが読み取り専用になります。つまり、コンテンツを変更しようとすると、セグメンテーション違反が発生します。
char amessage[] = "now is the time";
実際には、次の構文糖衣です。
char amessage[] = { 'n','o','w',' ','i','s',' ','t',
'h','e',' ','t','i','m','e','\0' };
つまり、16 文字の配列を作成し、その内容を文字列 "now is the time" (NULL ターミネータと共に) で初期化します。
一方で
char *pmessage = "now is the time";
同じ文字列データを読み取り専用データのどこかに置き、そのアドレスをポインターに割り当てますpmessage
。これは次のように機能します。
// This one is in the global scope so the array is not on the stack
const char _some_unique_name[] = "now is the time";
char *pmessage = _some_unique_name;
_some_unique_name
プログラム内の他の識別子と衝突しないように選択されています。通常、C 言語では許可されていないが、アセンブラとリンカでは使用できる記号が使用されます (例: のようなドットstring.1634
)。
ポインターの値を変更することができます。これにより、別の文字列など、別のものを指すようになります。ただし、配列の名前の背後にあるアドレスを変更することはできません。つまりamessage
、最初に割り当てられた同じ配列ストレージを常に参照します。
amessage[i]
orを使用して各文字列の個々の要素を参照できますが、読み取り/書き込みメモリに配置されているpmessage[i]
の要素にのみ割り当てることができます。amessage