私はCが初めてで、この質問があります。次のコードがクラッシュする理由:
int *a = 10;
*a = 100;
おそらくプログラムに割り当てられていないメモリ位置 0x0000000A に 100 を書き込もうとしているためです。あれは、
int *a = 10;
ポインタ 'a' が値 10 を持つメモリ内の場所を指すという意味ではありません。これは、メモリ内のアドレス 10 (0x0000000A) を指していることを意味します。次に、そのアドレスに何かを書き込みたいのですが、割り当てられていないため、そうする「権利」がありません。
次のことを試すことができます。
int *a = malloc(sizeof(int));
*a = 100;
これは機能しますが、恐ろしく非効率的です。単一の int だけが必要な場合は、それをheap ではなくスタックに入れる必要があります。32 ビット アーキテクチャでは、ポインターは 32 ビット長で、int も 32 ビット長であるため、int へのポインター構造は、4 バイトではなく 8 バイトのメモリ空間を占有します。また、キャッシングの問題についても触れていません。
任意の値 (10) ではなく、メモリ位置にポインターを割り当てる必要があります。
int cell = 10;
int *a = &cell; // a points to address of cell
*a = 100; // content of cell changed
Cに注意することについて、別の質問に対する私の回答を参照してください。
intにメモリを割り当てるためにmalloc()を使用することを提案するすべての回答に対して、malloc()の使用を少し変更することを提案したいと思います。それ以外の:
a = malloc(sizeof(int));
変数の型を繰り返さないことをお勧めします。これは、コンパイラーによって認識されており、手動で繰り返すことで、コードの密度が高くなり、エラーのリスクが生じるためです。後で宣言をegに変更した場合
long *a;
割り当てを変更しないと、間違った量のメモリを割り当てることになります(通常、32ビットマシンint
でlong
は、同じサイズであることがよくあります)。それは、IMO、使用する方が良いです:
a = malloc(sizeof *a);
これは単に「aが指すタイプのサイズ」を意味します。この場合int
は、もちろん正確です。上記のように宣言のタイプを変更した場合でも、この行は正しいです。割り当ての左側にある変数の名前を変更すると、リスクが残りますが、少なくとも、不必要に情報を繰り返すことはなくなります。
また、実際のオブジェクト(つまり変数)で使用する場合は括弧は不要でありsizeof
、キャスト式のように見える型名のみであることに注意してください。sizeof
関数ではなく、演算子です。
次の行、
int *a = 10;
整数aへのポインタを定義します。次に、ポインター a をメモリー位置 10 にポイントします。
次の行、
*a = 100;
a が指すメモリ位置に値 100 を置きます。
問題は:
aにメモリを割り当てたことがないためです。a へのポインターにスタック スペースを割り当てました。
int *a = NULL; a = malloc (sizeof (int)); if (a != NULL) { *a =10; }
動作します。
または、既存の変数のアドレスを指定することもできます。これも同様に機能します。
すなわち
int a* = NULL; int b = 10; a = &b;
これは、次のようなことをすることを意味します
*a = 100;
また、b を == 100 に設定します
これをチェックしてください: http://home.netcom.com/~tjensen/ptr/pointers.pdf
int へのポインターを宣言しているため、ポインターを 10 (アドレス) に初期化してから、このアドレスの int に値を割り当てようとします。アドレス 10 のメモリはプロセスに属していないため、クラッシュが発生します。これはうまくいくはずです:
int *a;
a = malloc(sizeof(int));
*a = 10;
printf("a=%i\n", *a);
free(a);
このコードはコンパイルできますか? int *
次のようにキャストしない限り、 10 は に変換できません。
int *a = (int *) 10;
*a = 100;
その場合、メモリ アドレス 10 に 100 を書き込もうとしています。これは通常、有効なメモリ アドレスではないため、プログラムがクラッシュします。
アクセスできないメモリの一部にポインタを割り当ててから、そのメモリの場所に値を割り当てているため、おそらくクラッシュしています(これは許可されていません!)。
次のように書くこともできます。
int* a = 10;
*a = 100;
最初の行の間隔が異なることに注意してください。流行っているスタイルではありませんが、個人的にはスッキリした感じです。コンパイラにとってはまったく同じ意味です。
次に、声に出して読みます。
"Pointer-to-int 'a' becomes 10"
"Value-pointed-to-by 'a' becomes 100"
実際の値を代入します。
"Value-pointed-to-by 10 becomes 100"
...ここで、10 が使用できるメモリを指している可能性が低いことに気付きます。
リテラルを使用してポインターに代入することはほとんどありません。
int* ptr = (int*)10; // You've guessed at a memory address, and probably got it wrong
int* ptr = malloc(sizeof(int)); // OS gives you a memory address at runtime
絶対メモリアドレスを直接指定する非常に低レベルのジョブがいくつかあると思います。たとえば、カーネルの実装?
さて、今日は最も簡単な説明をしようとしていますが、全体像をより詳細に説明しようとしています. 括弧をいくつか追加しましょうか。
(int*) a = 10;
(*a) = 100;
アドレス範囲 [10-13] に 4 バイトを書き込もうとしています。通常、プログラムのメモリ レイアウトはより高い位置から開始されるため、アプリケーションは、機能する可能性のある場所 (.data、.bss、およびスタックなど) から何かを誤って上書きすることはありません。したがって、アドレス範囲が割り当てられていないため、代わりにクラッシュするだけです。
ポインタはメモリ位置を指し、C の静的型付けはポインタの型を定義します。ポインターは簡単にオーバーライドできますが。単に:
(void*) v = NULL;
ここで、さらに物事に進みます。ヌルポインタとは何ですか? アドレス 0 を指す単なるポインタです。
ポインターの構造体型を指定することもできます。
struct Hello {
int id;
char* name;
};
...
struct Hello* hello_ptr = malloc(sizeof Hello);
hello_ptr->id = 5;
hello_ptr->name = "Cheery";
さて、mallocとは何ですか?Malloc はメモリを割り当て、割り当てられたメモリへのポインタを返します。次の型シグネチャがあります。
void* malloc(size_t size);
保守的なガベージ コレクタがない場合、メモリが自動的に解放されない可能性があります。したがって、割り当てたばかりのメモリを再び使用できるようにするには、次の手順を実行する必要があります。
free(hello_ptr);
実行する各 malloc には size-tag が含まれているため、フリールーチンで指定したチャンクのサイズを指定する必要はありません。
わかりました、まだ 1 つ、文字列はメモリ内でどのように見えるでしょうか? たとえば、「Cheery」に似たもの。簡単な答え。これは、ゼロで終わるバイト配列です。
0.1.2.3.4.5. 6
C h e e r y \0