none
ポインターのポインターを関数の引数で得るにはどうしたら良いですか?

    質問

  • ポインターの配列を利用しているプログラムをポインターのポインターに書き換えようとしています。

    void MainProg()
    {
    short **phimage; // 元々は short *phimage[YMAX] で定義されている。

    // この形では上手く
    phimage = (short **)malloc(xMax * yMax * sizeof(short));
    for (int i = 0; i < yMax; i++) {
    phimage[i] = (short *)malloc(xMax * sizeof(short));
    }

    // このような形で利用したいが、上手く行きません。
    TestMalloc(phimage);  
    }

    void TestMalloc(short **image)
    {
    image = (short **)malloc(xMax * yMax * sizeof(short));
    for (int i = 0; i < yMax; i++) {
    image[i] = (short *)malloc(xMax * sizeof(short));
    }
    }

    色々やってみたのですが、上手く行きません。どうしたら良いでしょうか?



    mnicksashimisan

    2018年2月5日 1:39

回答

  • ポインタが複数付くと私もよくこんがらがりますが

    関数の中で、関数に渡される引数自体に何か代入したいときは、その引数に機械的にポインタの * を付加するとよいです。

    ご質問の例だと TestMalloc 関数は引数の **image 自体に代入しようとしているので、ポインタの * を付加して、下記のように記述するとよいと思います。

    void TestMalloc(short ***image)
    {
    	*image = (short **)malloc(yMax * sizeof(short*));
    	for (int i = 0; i < yMax; i++) {
    		(*image)[i] = (short *)malloc(xMax * sizeof(short));
    	}
    }
    • 編集済み kenjinoteMVP 2018年2月5日 3:58 ご指摘の通りコードを修正しました
    • 回答としてマーク mnicksashimisan 2018年2月5日 7:35
    2018年2月5日 2:24
  • *image = (short **)malloc(xMax * yMax * sizeof(short));
    本題ではないですが、ここの部分のサイズが間違っています。ここで確保するのは、yMax個のshort*です。
    2018年2月5日 2:46
  • 説明不足ですみません。

    *image[i] と書いてしまうとコンパイラは演算子の優先順位により *(image[i]) と解釈します。*(image[i]) は、定義されていないポインタ image[i] の先を示しています。こちらへ代入することはできません。

    一方 (*image)[i] は malloc によって確保されたポインタ配列にポインタを代入しようとしているので問題ありません。

    2018年2月5日 7:06

すべての返信

  • ポインタが複数付くと私もよくこんがらがりますが

    関数の中で、関数に渡される引数自体に何か代入したいときは、その引数に機械的にポインタの * を付加するとよいです。

    ご質問の例だと TestMalloc 関数は引数の **image 自体に代入しようとしているので、ポインタの * を付加して、下記のように記述するとよいと思います。

    void TestMalloc(short ***image)
    {
    	*image = (short **)malloc(yMax * sizeof(short*));
    	for (int i = 0; i < yMax; i++) {
    		(*image)[i] = (short *)malloc(xMax * sizeof(short));
    	}
    }
    • 編集済み kenjinoteMVP 2018年2月5日 3:58 ご指摘の通りコードを修正しました
    • 回答としてマーク mnicksashimisan 2018年2月5日 7:35
    2018年2月5日 2:24
  • *image = (short **)malloc(xMax * yMax * sizeof(short));
    本題ではないですが、ここの部分のサイズが間違っています。ここで確保するのは、yMax個のshort*です。
    2018年2月5日 2:46
  • 逆にyMax行xMax列の長方形となる配列であれば、array of arrayでなく

    short* image = (short*)malloc(yMax * xMax * sizeof short);

    だけで済ました方がメモリ効率がよくなるためパフォーマンスも向上するんですよね。

    ところで元質問者さんに確認ですが、このコードはC++言語でしょうか? もしそうならそもそもmallocを使うべきではありません。C言語の場合、xMaxとyMaxはコンパイル時定数でしょうか、それとも実行時に決まる変数でしょうか?

    2018年2月5日 4:51
  • ***image を使ったやり方も試してはいたのですが、ダメでした。
    今回、指摘して頂いた点も含め下のようにしましたが、2回目のループの所でダメになります。

    void MainProg()
    {
    short **phimage;

    TestMalloc(&phimage);  
    }

    void TestMalloc(short ***image)
    {
    *image = (short **)malloc(yMax * sizeof(short *));
    for (int i = 0; i < yMax; i++) {
    *image[i] = (short *)malloc(xMax * sizeof(short));
    }
    }


    > short* image = (short*)malloc(yMax * xMax * sizeof short);
    > だけで済ました方がメモリ効率がよくなるためパフォーマンスも向上するんですよね。
    PCのメモリが小さいころ、大学の先生が作られたプログラムで、
    解法の概念を理解することも難しく、途中は数学の途中結果の浮動小数点で、
    バグが入っても大変になりますので、なるべく本体のプログラムを触らないで変更できたらと思っています。。

    > ところで元質問者さんに確認ですが、このコードはC++言語でしょうか? 
    > もしそうならそもそもmallocを使うべきではありません。
    C++です。何を使うべきですか?

    > C言語の場合、xMaxとyMaxはコンパイル時定数でしょうか、それとも実行時に決まる変数でしょうか?
    実行時に変更できるように改造しているところです。

    mnicksashimisan

    2018年2月5日 6:00
  • 説明不足ですみません。

    *image[i] と書いてしまうとコンパイラは演算子の優先順位により *(image[i]) と解釈します。*(image[i]) は、定義されていないポインタ image[i] の先を示しています。こちらへ代入することはできません。

    一方 (*image)[i] は malloc によって確保されたポインタ配列にポインタを代入しようとしているので問題ありません。

    2018年2月5日 7:06
  • 上手く行きました。
    また、大変勉強になり、ありがとうございました。

    mnicksashimisan

    2018年2月5日 7:34
  • 本体を触らない方針ということで採用は難しいかもしれませんが提案だけしておきます。2次元のshortであればstd::vectorを使って

    std::vector<std::vector<short>> image;

    とするのが一般的です。またC言語より表現が柔軟なため、引数でアドレスを受け取るようなことはせずreturn文で値を返します。そのためTestMalloc()が行う処理としては

    auto TestMalloc() {
        return std::vector<std::vector<short>>(yMax, std::vector<short>(xMax));
    }
    

    と書けます。呼び出し方法もシンプルで

    auto image = TestMalloc();

    と = で受け取れますし、コンパイラーが型を把握できているためautoで済みます。メモリ管理はstd::vectorが行っていますが配列と同じようにアクセスできるため

    image[5][5] = 10;

    のように書けます。

    2018年2月5日 13:17
  • 見慣れないコーディングですけど、少し勉強してみます。

    mnicksashimisan

    2018年2月6日 4:57