2012-02-23 2 views
4

次のコードを書きましたが、メモリを割り当てなかった構造体のメンバーにアクセスしようとするとクラッシュすると考えました。しかし、私はC++が自動的に構造体のメモリを割り当てたことにかなり驚いていました。それは正常な行動ですか?比較のために、オブジェクトへのポインタを宣言し、実際にオペレータ "new"でオブジェクトを作成せずにメンバにアクセスしようとすると、プログラムがクラッシュします。私は信じられないときにそれがなぜ機能するのか不思議です。C++で構造体へのポインタを宣言すると、そのメンバに自動的にメモリが割り当てられます。私が間違っている?

これは私のプログラムです:

#include <stdio.h> 

struct Produto 
{ 
    int codigo; 
    float preco; 
}; 

int main() 
{ 
    struct Produto* sabonete; 
    sabonete->codigo = 654321; 
    sabonete->preco = 0.85; 

    printf("Codigo = %i\n", sabonete->codigo); 
    printf("Preco = R$ %.2f\n", sabonete->preco); 

    return 0; 
} 

は、OS:Windows 7の
はコンパイラ:MinGWのGCC 4.6.1

+2

あなたは間違っています。これはちょうど*動作するように見えます - それは未定義の動作です。 – jrok

+6

あなたのコードのバグを修正すれば、謎は解消されます。壊れたコードは奇妙なことをします、それはそうです。 –

+0

あなたが言ったことの重要な問題は、 "C++は構造体のメモリを自動的に割り当てました"。いいえ、それはしなかった。ポインタはちょうどmemアドレスですが、ポインタはどこにポイントしているのかわかりません。 – Avi

答えて

11

C++は自動的にメモリを割り当てることができませんでした。ポインタはあなたのプログラムのメモリ空間内の有効なアドレスであったばかりの任意の値を保持していますので、segfaultを取得しませんでした。あなたのプログラムは未定義の動作を示し、次回実行時に動作しない可能性があります。

未定義の動作ではなく、はクラッシュを保証します。そのため、未定義と呼ばれています。

+0

しかし、printfを実行すると、構造体のメンバーに割り当てた正確な値が出力されるので、実際には機能します。 –

+9

@FernandoAiresCastello:いいえ、実際はそうではありません。未定義の動作を呼び出しています。定義*何かが起こる可能性があります。あなたのコードは間違っています。 –

+0

@FernandoAiresCastelloもしあなたが動作しているかどうか、それが動作する頻度、そしてプロセス中に何枚のハードディスクを拭くか、それはどういう意味ですか?_actually_ works :) – sehe

4

あなたはそれが何でsaboneteポイント未定義だ2行目に未定義の動作

に遭遇しました。あなたがそれを変更すると何かを壊さないメモリを指し示すことができます。あるいは、あなたがそれを変更したときに核を起動するメモリを指すことができます。

C++はメモリをまったく割り当てていないため、何も破壊しないようにメモリを踏んでいるだけです。

2

全く反対です。そのポインタは初期化されておらず、逆参照によってUBを呼び出しています。ポインタが必要な場合は、既存のポインタを使用して、またはnewを呼び出すことによって初期化する必要があります(または、これはC++なので、割り当て/破棄を処理するためのコンテナとして機能するオブジェクト、つまりRAIIです)。

未定義の動作は、のいずれかがになる可能性があることを意味します。確かに、メモリのレイアウトのせいで何時でも動作するように見えるかもしれませんが、常にそうなるという保証はなく、このようなコードを書くべきではありません。

+0

私は、ポインタが任意のメモリアドレスを保持している場合、なぜこのコードを実行するたびに、この任意のメモリアドレスが構造を正確に指すのかということです。 –

+1

@FernandoAiresCastello:あなたはまだ混乱しているようです。未定義の動作を呼び出すときには、韻や理由はありません。 **動作は未定義です**。何かが起こるかもしれません、それが理由で理由を付ける必要はありません。そのポインタの上に変数宣言を追加すると、クラッシュが発生することがあります。多分そうではありません。繰り返しますが、**未定義の**動作。 –

+0

よろしくお願いします。値が構造体のメンバに正しく割り当てられているため、実際にはうまくいきました。しかし、私は通常これをやりません、私はいつもポインタを初期化します。私はちょうど何が起こるか見るために実験していました:) –

0

g ++コンパイラは、NULLに割り当てられていないポインタを初期化しないため、メモリ内の最初の外観のように見える部分を指している可能性があります。

あなたはボンネットの下「が起こってきた可能性があり、」何に興味がある場合はご質問、はい、あなたがあなたのオブジェクトにメモリを割り当てることを望んでいない通常の未定義の動作です:)

+0

これは競合状態ではありません。 –

0

に答えるために、お使いのプラットフォームのsaboneteが4バイト幅で(ポインタとして)、メインがパラメータを宣言していない(OSがいずれの場合でも使用可能になっている)ので、通常はパラメータの逆になる同じメモリ空間を占有する可能性があると考えてください注文。

char ** argvは、コマンドライン部分を含む文字列を指すポインタ配列(少なくとも16個以上含む)を指しています。

あなたは実際にあなたの値をそのアレイ上に書いていますが、それはあなたのプログラムに属しているので、OSは文句を言うことはありません。そして、あなたが元の値を参照することは決してありませんし、他の誰もそれらを変更しないので、すべてが正常に動作しています。

しかし、そうではありません。これはあなたが他の何かのために使用中のスペースにフィッティングすることが幸運だったからです - この場合は興味があります。

関連する問題