1

関数へのポインターを送信しようとしていますが、ポインターはポインターの配列の一部です

void func(A **pa)
{
     return;
}


A *pa;
pa=(A*)malloc(2*sizeof(A));

したがって、配列の最初の項目pa[0]は簡単に送信できます(ポインターが指す場所であるため)

func(&pa);

しかし、今私は行き詰まっています、どうすれば2番目のアイテムを送ることができますか?pa[1]

のようなものを試しましfunc(&pa + 1*sizeof(A)); たが、うまくいかなかったようです。

4

4 に答える 4

2

注:この回答は、4時間前にOP(元のポスター)である@hudacが行った説明を反映するように更新されています。尋ねられた質問は有効であり、非常に興味深いものです。そうは言っても、OPのコードを単純化する方法があるかもしれません。元の質問に答えた後、それらを見ていきます。

まず、OPの最近の説明に従って、Aとfuncの定義例を示すことにより、質問のコードをもう少し具体的にしようとします。

typedef struct { int x; int y;} A;

void func(A **ppa)
{
   printf("(%d,%d)\n",(*pa)->x,(*pa)->y);
}

次に、質問と回答の両方に適切なコンテキストを提供するコードをいくつか示します。

void main() {
    A *pa;  
    pa = (A*) malloc(2 * sizeof(A));

    pa[0].x = 3;    pa[0].y = 4;
    pa[1].x = 13;    pa[1].y = 42;

    func(&pa);      
    //the answer to the question goes here
}

現状の質問は、動的に割り当てられたAの配列の2番目paの要素へのポインターへのポインターを渡す方法を求めています。OPは、pafunc(&pa);)の最初の要素へのポインターへのポインターの受け渡しに成功し、ポインター演算を使用して2番目の要素へのポインターへのポインターの受け渡しを試みましたが、もちろん期待どおりには機能しませんでした。OPのコードを考えると、与えられた答えはどれも正しいとは言えません。これは非常に興味深い質問であることがわかります。funcA*ではなくA**を期待すると、物事が必要以上に複雑になります。OPが直面した問題を理解せずに物事を単純化することは可能ですが、これでは、ポインター演算を正しく行うことがなぜそれほど困難であったか(実際には不可能であったか)についての洞察は得られません。

基本を再検討するための小さな迂回:代入がある場合は、左辺値(左側の式)と右辺値(右側の式)があります。左辺値はアドレスを持つものであり、右辺値には、割り当てが左辺値のアドレスに格納する値があります。例:x = 5; 式には、左辺値と右辺値の両方(xなど)が含まれる場合と、右辺値のみ(5など)が含まれる場合があります。演算子&は、左辺値、つまりメモリアドレスを持つもの、つまりxなどにのみ適用されますが、5などには適用されません。

質問に戻ります。paはタイプA*ですが、funcはタイプA**の引数を想定しています。OPは、paの最初の要素で機能するようにfuncを呼び出す方法を問題なく理解しました。

func(&pa);

これはpaの最初の要素に取り組んでいるfuncへの呼び出しであるというコメントと一緒に、このコードを少し与えるのは非常に難しいことに注意してください。関数funcはpa[0](別名* pa)、つまりタイプAの何かで動作する必要がありますが、funcが定義されているため、タイプAの&paを渡します** !!! より適切な引数タイプで関数を定義することにより、この問題に後で対処します。今のところ、私は自分が持っているもので作業しようとします。

OPなどがpaの2番目の要素で機能するfuncの呼び出しを行うのが非常に難しいと感じた理由は、必要なのは、値がメモリのビットのアドレスを保持するポインタ式であるためです。 paの2番目の要素。paの2番目の要素のアドレスはどこにも保存されていないため、このようなポインタの使用はありませ。(大文字が目を痛めた場合はお詫びします:-)これをできるだけ明確にする必要がありました!)paの2番目の要素へのアクセスは、1番目の要素のアドレス(paが保持するもの)を使用したポインター演算によるものです。 。

それは質問に答えることが不可能であるという意味ではありません。それは、答えが予想外で厄介なハックになることを意味します。したがって、質問でmain()に別の変数を導入できないと仮定すると、funcを呼び出すためにpaを変更し、厄介な驚きなしにpaを操作できるように戻す必要があります。後でmain()で。

pa++; func(&pa); pa--;

これがOPの質問に対する答えです。現在ここに投稿されている他の回答は、さまざまではるかに単純な質問に答えようとしています。しかし、元の質問ははるかに興味深いものであり、今では答えがあります:-)しかし、答えよりも興味深いのは、大文字を使用して強調した観察です。

私たちの正気を取り戻すために、私たちはfuncの定義でなされた選択を再考する必要があります。

配列に格納されているAにアクセスすることだけが必要な場合は、ポインターへの依存を完全に排除することを検討できます。

typedef struct { int x; int y;} A;
void bar(A a)
{
   printf("(%d,%d)\n", a.x, a.y);
}
void main() {
    A *pa;  
    pa = (A*) malloc(2 * sizeof(A));

    pa[0].x = 3;    pa[0].y = 4;
    pa[1].x = 13;    pa[1].y = 42;

    bar(pa[0]);      
    bar(pa[1]);
}

関数に単純なAではなくA*引数をとらせることを検討する理由は2つあります。1。関数が指すAを変更する必要がある場合、および/または2. Aがたまたま大きな構造体である場合、および関数を呼び出すたびに、大量のメモリがスタックにコピーされることは望ましくありません。

typedef struct { int x; int y;} A;
void foo(A *a)
{
   int tmp = a->x;
   a->x = a->y;
   a->y = tmp;
}
void bar(A a)
{
   printf("(%d,%d)\n", a.x, a.y);
}
void main() {
    A *pa;  
    pa = (A*) malloc(2 * sizeof(A));

    pa[0].x = 3;    pa[0].y = 4;
    pa[1].x = 13;    pa[1].y = 42;

    foo(&pa[0]); //or alternatively: foo(pa);
    bar(pa[0]);  //or alternatively: bar(*pa);

    foo(&pa[1]); //or alternatively: foo(pa + 1);
    bar(pa[1]);  //or alternatively: bar(*(pa+1));
}

OPに役立つ可能性のあるもう1つの注意点は、ポインター演算を実行する際に、ポインターのタイプが役割を果たすということです。したがって、pa + 1の数値は、paの数値にsizeof(A)を加えたものに等しくなります。(これは、次の呼び出しでpaの2番目の要素でfuncを機能させる試みの失敗に関連しています:func(&pa + 1 * sizeof(A)))

OPへの最後の注意:func内にA **ポインターを取得し、それに別のポインターを割り当てるなどの面白いことを行う計画があったためにfuncの署名を変更したくない場合(たとえば、新しいmalloc( )-割り当てられたメモリのチャンク)、あなたは地雷原に歩いているでしょう!関連性があると思われる別の質問に対する私の回答を確認してください。line2の無料でmemcpyが何もしないのはなぜですか?mallocが大丈夫になる前に無料ですか? 物語の教訓は、ポインターは有用ですが、概念の複雑さとエラーの可能性は、*ごとに指数関数的に増大するということです(そして多くの場合、より良い選択肢があります):-)

于 2012-11-28T09:15:06.117 に答える
2

あなたが探している&pa[1]

func (&pa[1]);   // call function with second element of pointer array

ちなみに、2つのポインターだけの配列を割り当てるつもりかどうかはわかりませんが、割り当てている場合は、mallocにエラーがあります。そのはず

pa = malloc (2 * sizeof(A*));  // note the addition of * after "A"

あなたがしているのは、2倍のサイズを割り当てることですA。これはおそらく数千バイトの長さになる可能性があります。そのようなオブジェクトへのポインタには、それほど多くのスペースは必要ありません。

また、ではC、のリターンタイプをキャストする必要はありませんmalloc()

于 2012-11-28T06:23:14.277 に答える
2

Aの配列へのポインタを渡したい場合は、次のようにする必要があります。

func(&pa[0]); 
func(&pa[1]);

しかし、それが配列の場合、配列自体へのポインターと配列のサイズを渡すだけではいけませんか?これは基本的に最初の行のみを意味します。

ポインターの配列にポインターを渡したい場合は、まったく別の方法で行う必要があります。

A **pa;
pa=(A**)malloc(2*sizeof(A*));

ただし、各Aをmallocし、それに応じてFuncを変更する必要もあります。

またfunc(&pa + 1*sizeof(A))、ポインタの数学のために機能しないことにも注意してください。必要なのは必要なだけfunc(&pa + 1)で、残りはコンパイラが処理して配列の2番目のメンバーを取得します。

于 2012-11-28T06:36:53.817 に答える
1

これを試して :

func(&pa[0]); // for 1st object 
func(&pa[1]);// for 2nd object

paAの配列のアドレスを &pa提供します。配列全体のアドレスを提供します。

意味、

A * ptr;

ptr = pa ;// increment `ptr` will give you next element in same array
ptr = &pa ;// increment `ptr` will give you the next array of that type

また、関数のfuncシグネチャを次のように変更します

void func(A *pa)
{
     return;
}

================================================== ==========

ポインタの配列をに渡したい場合func

このようにしてください:

A **pa = malloc(2*sizeof(A*));

そしてそれを次のように送信します

func(&pa[0]);
func(&pa[1]);

そしてfunc_

void func(A **pa)
{
     return;
}
于 2012-11-28T06:23:56.253 に答える