アプリの実行中、ポインタの位置はどのように追跡されますか?
ポインタは他の変数として保存されます。通常は と同じサイズにunsigned long
なりますが、実装方法を理解するためだけに、これが保証されるわけではありません。コンパイラは多種多様な最適化を自由に行うことができるため、ポインタはメモリに格納されたり、レジスタに格納されたり、最適化された場合に仮想エンティティとしてのみ存在したりする可能性があります。
次のコードを検討してください。
void foo(void) {
char *c;
char buf[100];
for (c=buf; c < buf+100; c++ {
c = '0';
}
}
この場合、変数は、配列内のすべての文字にc
ASCII 文字を書き込むために使用されています。この関数を超えて存在しないため、レジスタにのみ存在する可能性があります。(このコードを記述するより良い方法があります。)0
buf
c
次のコードを検討してください。
struct foo {
char name[10];
struct foo *next;
}
この場合のメンバnext
は、さらに別のオブジェクトへのポインタstruct foo
です。たとえば、これらのもののリンク リストです。これらのポインターは、これらのオブジェクトのコントラクトの一部であるため、メモリに格納する必要があります。つまり、そこに存在する必要があります。これらのポインターを回避する方法もありません。ポインターが指すオブジェクトは、プログラマーの気まぐれで他のオブジェクトに置き換えることができます。また、これらのオブジェクトの数は実行時に完全に決定されるため、コンパイラは、スタックに割り当てられた変数の場合のように、シンボル テーブル内のアドレスを追跡することはできません。
では、ポインタが保持するアドレスに格納されているオブジェクトを直接変更するにはどうすればよいでしょうか?
これは、コードでの例の文字列の使用によって複雑"foo"
になります。これらはプロセス アドレス空間の読み取り専用メモリに保存されるため、変更することはできません。(驚き!) 別のメソッドで文字列を初期化すると、ポインターを介してデータを変更できます。
char *c = malloc(10);
strcpy(c, "hello");
c[0] = 'H';
printf("c: %s\n", c);
これにより、ポインターを介して使用可能な割り当てられたスペースにh
withが上書きされます。ポインターを配列であるかのようにアクセスすることは、ポインター アクセスを次のように書き直すことと同じです。H
c
c[0] = 'f';
c+0 = 'f';
実際、配列へのアクセスはよく似ています。配列の名前は、最初の要素へのポインタと同じです。
少し複雑です。Expert C Programmingという本は、ポインタを驚くほど詳細にカバーしており、お金を払うだけの価値があります。