2011-02-08 23 views
1

ノードのデータを更新できるリンクリストを作成しようとしていますが、何をしようとしても、Cはvoidポインターの値を更新することができません。に)。ここで私が持っているテストコードがあります:関数を介してポインタをvoidに変更するにはどうすればよいですか?

だけ出力
void newData(void * d) 
{ 
    char data[] = "world"; 

    d = &data; 
} 

int main() 
{ 
     char testData[] = "hello"; 
     void * testPointer = &testData; 

     printf("TestData is %s\n", (char *)testPointer); 

     // Modify the data 
     newData(&testPointer); 

     printf("TestData is %s\n", (char *)testPointer); 
} 

::

TestData is hello 
TestData is hello 

私はここに明らかに何かが足りないのですか?私はまた、ポインタへのポインタを使用しようとしましたが、役に立たない。

+2

引数の型が間違っている、それが空でなければなりません:

newData(testPointer); 

+0

または単にそれを 'newData(testPointer); 'と呼びますか? – John

+0

'void * testPointer =&testData;'この演算子ではアドレス演算子は不要です。配列にポインタを割り当てると、配列のアドレスgetが割り当てられます。ですから、代わりに 'void * testPointer = testData;'を実行することができます。あなたがこれを行うことができるあなたのプログラムにも他のステートメントがあります。 – Mahesh

答えて

4

2つのことは、これで間違っている:

char data[] = "world"; 

は、関数のスタックフレームの一部として作成おそらくです。配列はポインタに劣化します。そのため、関数がretを呼び出すと、スタックをクリーンアップし、そのアドレスのメモリがなくなっているはずです。何らかの操作がここで働くのであれば、まだメモリを上書きしていないからです。

あなたは何をすることができますか?宣言します。staticは、プログラムライフタイムの存在を保証する(つまり、スタックには割り当てられず、データセグメントに割り当てられ、メインライブラリの前にCライブラリによって割り当てられます)。あなたが内容をコピーして値を指していないので、

char data[] = "world"; 
memcpy(d, data, 5); 

は、完全に有効です:私は、これは単なるデモである疑いがあるため、しかし、指摘する価値があります。

newData(&testPointer); 

あなたはここで簡単な間違いをしています。アセンブリ内のポインタは、別のメモリアドレスを保持するメモリアドレスです。関数へのポインタを渡すと、そのメモリアドレスを渡したいので、その関数を呼び出すと、ポインタの内容であるメモリアドレスが新しいポインタの形でスタックにコピーされます。もちろん、これらの両方のポインタは同じことを指しています。これは、参照渡し型のものを実現する方法です。あなたが私を信じていないなら、デバッガで見てください。

しかし、何をしているのかはポインタのアドレスを渡すことで、値へのポインタへのポインタを作成しています。

|Address|Value 
|0x120 |0x121 <-- this is what you're passing with &testPointer 
|0x121 |0x122 <-- this is a pointer; it contains the address of a value 
|0x122 |h  <-- this is a value. 
|0x123 |e 
|0x124 |l 
... 

このような記憶を想像してみてください。私の単純な記憶では、0x121ではなく0x120を渡しています。もちろん、逆参照を2回行うことはできますが、なぜですか? **

void newData(void ** d) 
{ 
    char* data = "world"; 

    *d = data; 
} 
+0

別の回答へのコメントで説明したように、ローカル変数 'data'はスタックにありますが、プログラムのデータセグメントに "world \ 0"が存在するため、data [] = "world"が有効です。 – user47559

+0

それを考えるもう一つの方法は、 'data'はスタック上のローカル変数ですが、スタック上にない場所を指しています。 – user47559

7

私はしかし、これは「世界は」ローカルスタックされたとして、それは、自身の問題だた、とあなたはあるnewDataから戻った後、有効になりませんあなたが

void newData(void ** d) 
{ 
    char data[] = "world"; 
    *d = &data; 
}  

が必要だと思います。

+2

const char * data = "world"に変更してもうまくいくと思います。 "world"はバイナリの中でハードコーディングされた文字列になります。 – TheBuzzSaw

+0

これは、新しい値のためにさらにスペースを割り当てる必要があることを意味しますか、それとも簡単な方法がありますか?私は単にtestPointer内の文字列を変更したいだけです。 – Lewis

+2

@Lewis:文字列 "inside"テストポインタがありません。 Cスタイルの文字列はそのようには動作しません。基本的にCスタイルの文字列は、文字シーケンスの最初の文字へのポインタです。だからこの文字列は何とか存在しなければならない。リテラルをcharポインタ( 'char * data =" world "')に代入すると、 '' world \ 0 "'を含むcharシーケンスがコンパイラによって暗黙的に作成され、プログラムデータに格納されます。したがって、代入は以前に割り当てられたデータのアドレスを変数に代入するだけです。 – Vlad

0

が、私はほとんど変化がコードは、問題を解決することができていると思う:簡単な解決策は、ちょうどこのようなポインタを渡すことです。
関連する問題