質問
私はCが初めてで、この質問があります。次のコードがクラッシュするのはなぜですか:
int *a = 10;
*a = 100;
解決
プログラムに割り当てられていない可能性のあるメモリ位置0x0000000Aに100を書き込もうとしているためです。つまり、
int *a = 10;
は、ポインタ「a」が値10のメモリ内の場所を指すことを意味しません。メモリ内のアドレス10(0x0000000A)を指していることを意味します。次に、そのアドレスに何かを書きたいが、「権利」を持っていない割り当てられていないため、そうするために
次を試すことができます:
int *a = malloc(sizeof(int));
*a = 100;
これは機能しますが、恐ろしく非効率的です。単一のintのみが必要な場合は、ヒープではなくスタックに配置する必要があります。 32ビットアーキテクチャでは、ポインターの長さは32ビットで、intの長さも32ビットなので、ポインターへのポインター構造が使用されます(少なくとも)この方法で8バイトのメモリ空間4ではなく。キャッシュの問題についても言及していません。
他のヒント
任意の値(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));
変数の型を繰り返さないことをお勧めします。これは、コンパイラによって認識されており、手動で繰り返すとコードがより密になり、エラーリスクが発生するためです。後で宣言を変更した場合(例:
)long *a;
割り当てを変更しないと、間違った量のメモリを割り当てることになります(一般的な場合、32ビットマシンでは int
と long
は同じです。サイズ)。 IMOの方が良い:
a = malloc(sizeof *a);
これは単に「aが指す型のサイズ」を意味し、この場合は int
であり、もちろん正確です。上記のように宣言内のタイプを変更しても、この行は依然として正しいです。割り当ての左側で変数の名前を変更しても、少なくともリスクはありますが、少なくとも不必要に情報を繰り返すことはありません。
また、実際のオブジェクト(つまり変数)で使用する場合、 sizeof
では括弧は不要であり、キャスト式のように見える型名でのみ必要であることに注意してください。 sizeof
は関数ではなく、演算子です。
aにメモリを割り当てたことがないため。ポインタへのスタックスペースを割り当てたところです。
int *a = NULL; a = malloc (sizeof (int)); if (a != NULL) { *a =10; }
動作します。
別の方法として、既存の変数のアドレスを指定することもできますが、これも同様に機能します。
i.e。
int a* = NULL; int b = 10; a = &b;
これは、次のようなことを行うことを意味します
*a = 100;
bも== 100に設定します
これをチェックしてください: http://home.netcom.com/~tjensen/ptr/pointers.pdf
次の行、
int *a = 10;
整数へのポインタを定義します a 。次に、メモリ位置10へのポインタaをポイントします。
次の行、
*a = 100;
aが指すメモリ位置に値100を挿入します。
問題は次のとおりです:
- どこを指しているのかわかりません。 (メモリ位置10の値がわかりません)
- ポイントを問わず、その値を変更する権利はおそらくないでしょう。おそらく他のプログラム/プロセスのメモリです。泥棒よ!
intへのポインターを宣言し、ポインターを10(アドレス)に初期化してから、このアドレスのintに値を割り当てようとします。アドレス10のメモリはプロセスに属していないため、クラッシュします。これは動作するはずです:
int *a;
a = malloc(sizeof(int));
*a = 10;
printf("a=%i\n", *a);
free(a);
このコードはコンパイルされますか? 10は、次のようにキャストしない限り、 int *
に変換できません。
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;
ここでさらに説明します。 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にはサイズタグが含まれているため、指定したチャンクのサイズを無料で指定する必要はありません。-
OK 「Cheery」に似たもの例えば。簡単な答え。ゼロで終わるバイトの配列です。
0.1.2.3.4.5. 6
C h e e r y \0