2017-07-31 5 views
0
struct mystruct{ 
    int* x; 
    float *y; 
    string *z; 
    mystruct(int* a,float* b, string *c): x(a), y(b), z(c){} 
}; 
void* create(){ 
    int a = 1; 
    float b = 2.2; 
    string c = "aaa"; 
    mystruct x(&a, &b, &c); 
    void* p = &x; 
    return p; 
} 
void print(void *p){ 
    mystruct* p1 = static_cast<mystruct*>(p); 
    cout << *p1->x << " " << *p1->y << " "<<*p1->z<< endl; 
} 
int main(){ 
    cout << sizeof(mystruct) << endl; 
    void* p1 = create(); 
    print(p1); 
    return 0; 
} 

コードの出力のようなある:24 1 2.76648e + 19 304 \ 203] 211 \ \ 303fffff \ 204UH 211 \ 345H \ \ 201 354 \ \ 220H} \。 \ 270H \ 211です。 私はそうです:24 1 2.2 aaaボイド*鋳造得る予期しない出力

私はvoid *ポインタキャストに何か問題があると思いますが、私は理由を理解できません。助けてもらえますか?

+2

*ローカル変数*へのポインタを返します。ローカル変数は、関数が終了すると有効範囲外になり、存在しなくなります。そのようなローカル変数へのポインタは無効になります。そのポインタを逆参照しようとすると、[*未定義の動作*](http://en.cppreference.com/w/cpp/language/ub)につながります。そしてあなたはそのような無効なポインタを4つ参照しないでください。要するに、この問題はあなたのキャスティングとは関係ありません。 –

+0

あなたが戻って 'p'を使う瞬間、プログラム全体の動作は未定義です。 – StoryTeller

+3

https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope?noredirect=1&lq=1 – Mat

答えて

4

あなたはこれで未定義の動作を作成:あり

void* create(){ 
    int a = 1; 
    float b = 2.2; 
    string c = "aaa"; 
    mystruct x(&a, &b, &c); 
    void* p = &x; 
    return p; 
} 

あなたはcreate自動ストレージスコープ(別名ローカル変数)内のオブジェクトへのポインタでmystructを初期化します。これらのオブジェクトは、すぐにcreateが返された時点で存在しなくなり、したがってポインタは無効になります。さらに、create関数内のmystruct自動ストレージオブジェクトへのポインタも返します。つまり、未定義の動作の上に未定義の動作を呼び出すようなものです。構造体の内側にポインタを使用して

停止:

EDITは、ここで提案するソリューションです。ポインターは常に,より大きいため、とにかくintまたはfloatへのポインターを渡すのは理にかなっていません。関数へのポインターやポインターを渡すと、どちらかが値をコピーすることで渡されますが、ポインターでは余分な間接的なステップがあります。関数が値を変更できる "参照"を渡すためにそれらを使用したい場合、数値型へのポインタを渡すことは意味があります。

ポインタを構造体に渡すと、構造体全体をコピーする必要はありません。

だから、私はあなたが全体でポインタを取り除くことをお勧めします。あなたは明らかに彼らがどのように動作しているのかまだ理解していないし、あなたがそこに持っているその特定のタスクについては、とにかく間違ったツールです。

+0

?浮動小数点は32ビット、ポインタは32ビットですか? – JHBonarius

+1

@JHBonariusポインタのサイズはプラットフォームに依存します(技術的には、 'int'と' float'のサイズは正確に指定されていません)。この答えに追加するには:C++でrawポインタをほとんど必要としません(いくつかの高度なローレベルプログラミングをしたい場合を除きます)。変数を値で保存し、 'std :: vector'の中に配列を格納し、参照でオブジェクトを渡すと、初心者のユースケースの99%がカバーされます。 – chtz

+1

@JHBonarius:32ビットマシン浮動小数点では、intとポインタはすべて32ビットです。標準のABIの1つに従う64ビットマシン(最近のマシンの大部分)では、floatとintはまだ32ビットですが、ポインタは64ビットです(long intは通常の64ビットABIで64ビットです。 Windows、Linux、および* BSD)。整数を64ビットにする場合は、int64_tまたはlong longを使用する必要があります。 – datenwolf