• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:ポインタのポインタの関数受け渡しについて)

ポインタのポインタの関数受け渡しについて

このQ&Aのポイント
  • ポインタのポインタを利用したプログラムを作成しています。
  • 配列のセットにはset関数を、表示に関する処理をpt関数で行いたいと思っています。
  • dt、set関数、pt関数の引数にはどのような値を入れればよいか理解できません。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.7

こんにちは。もう、解決しました? ポインタ・・・悩ましいですよね。ポインタのポインタ・・・配列、構造体。でもって、それを参照渡しとか、もう、変数の実体はどこ~?って感じです。どやって値を書くの、読むのと書き成れた人でも、試行錯誤でデバグするのではないでしょうか。 必ずしも、やまさんの疑問と一致しているとはいえないですが、次のことに注目してサンプルをくみ上げてみました。 (1) main()で、int形2次配列で出来たデータテーブルの位置を示すポインタdtを用意する。 (2) set()でデータテーブルの領域を確保する。確保した領域は、参照渡し引数dtに返す。ついでにデータテーブルにも値を入れてしまいます。 (3) ptでデータテーブルを表示する。 ---------- サンプルソース ここから ----- (注意) 整形のため全角スペースを使ってます。 (注意) 勝手に3x3の配列にしてます。 01: #include<stdio.h> 02: /* FUNCTION PROTOTYPE */ 03: void set(int***); 04: void pt(int**); 05: /* MAIN */ 06: int main(void){ 07:  int **dt; 08:  set(&dt); 09:  pt(dt); 10: } 11: /* DT MEMORY ALLOCATE AND SET SOME VALUE */ 12: void set(int ***dt){ 13:  int i,j,k; 14:  k=3; 15:  *dt=(int**)malloc(sizeof(int*) * k); 16:  for(i=0;i<k;i++){ 17:   (*dt)[i]=(int*)malloc(sizeof(int*) * k); 18:  } 19:  for(i=0;i<k;i++){ 20:  for(j=0;j<k;j++){ 21:   (*dt)[i][j]=i*k+j; 22:   printf("set (*dt)[%d][%d]=%d\n", i, j, (*dt)[i][j]); 23:  }} 24: } 25: /* DISPLAY DT */ 26: void pt(int **dt){ 27:  int i,j,k; 28:  k=3; 29:  for(i=0;i<k;i++){ 30:   for(j=0;j<k;j++){ 31:    printf("%d ", dt[i][j]); 32:   } 33:   printf("\n"); 34:  } 35: } ---------- サンプルソース ここまで ----- ちょびっと説明:ヒントになれば幸いです。 (1) setの引数dtのポインタの深さについて 5行目、12行目を見てください。確保したメモリの領域を返さなければなりませんので、2次元配列ポインタ**dtを示すアドレスを渡す為、***dtとしなければなりません。そして、mainからは、dtのアドレス&dtを渡さなければなりません。参照わたしですね。 (2)領域確保 main内のdtとset内の(*dt)は等価、同じ意味です。 一次元目の領域確保は、(*dt)に対しておこないます。2次元目の領域確保は、それぞれ(*dt)[i]に対しておこないます。僕の文力で説明できないです(大汗)。 (3) ポインタに書き込む、読み出す 21行目、22行目を見てください。(*dt)[i][j]です。ポインタを示す*印は、演算子というのですが、順位的に弱いことの多い演算子です。順位というのは、たし算とかけ算は、掛け算が先というような、解釈の順番です。配列や構造体が絡んできた時は、負けちゃいますので、いつも括弧でくくって守ってやっています。 どですか?  Magna

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (7)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.8

余談ですが, sizeof には sizeof (型) sizeof オブジェクト の 2つの形式があります. で, malloc で使うなら (安全のためにかっこを余計に付けるけど) x = malloc(sizeof (*(x)) * n); のように, 後者の形で使う方が安全だと思います. 今の例だと *dt = malloc(sizeof (*(*dt)) * k); とする. 左辺の *dt と sizeof の中の *dt を一致させれば, 常に正しいサイズで確保できます.

全文を見る
すると、全ての回答が全文表示されます。
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.6

★『char **alloc』を宣言しない場合 >一つ初歩的な質問なのですが、set関数の中で**allocを宣言していますが、 >しない場合はどのように記述するべきなのでしょうか。 >*dt = (int**)… > >*dt[i] = (int*)… >のようにしてもだめですよね。  ↑  (*dt) = (int**)malloc( sizeof(int*) * k );  (*dt)[ i ] = (int*)malloc( sizeof(int) * k );  となります。  1つ目の dt にはカッコは必要ないです。  2つ目の dt にはカッコを付けないと意味が変わってきます。  ※安全策として malloc で確保できなかった場合の処理も書いておきましょう。 >二つ目のmallocの件、ありがとうございます。 >見落としていました。  ↑  私も見落としてしまいました。 ・過去質問より次のリンクを紹介しておきます。  動的に二次元配列を確保する場合の方法です。  http://oshiete1.goo.ne.jp/qa3022605.html→『callocで二次元配列を作成するには?』  ↑  この方法なら malloc、free の回数が減るためエラーチェック、解放なども早くなります。  最後に int ** で使える二次元配列の確保と解放関数を紹介しておきます。 サンプル: #include <stdio.h> #include <stdlib.h> // n×nの二次元配列を確保 int **alloc_matrix( int n ) {  int **aa;  int *a;  int i;    if ( (aa = (int **)calloc(n + 1,sizeof(int*))) != NULL ){   if ( (a = (int *)calloc(n * n,sizeof(int))) != NULL ){    for ( i = 0 ; i < n ; i++ ){     aa[ i ] = &a[ i * n ];    }    aa[ n ] = NULL;   // ちょっとした工夫    return aa;    // 正常   }   free( aa );  }  return NULL;     // エラー } // n×nの二次元配列を解放 int **free_matrix( int **a ) {  if ( a != NULL ){   free( a[0] );   free( a );  }  return NULL; } // 使い方 int main( void ) {  int **p;    // 10×10の二次元配列を確保  if ( (p = alloc_matrix(10)) != NULL ){    :   (処理)    :   p = free_matrix( p );  }  return 0; } 以上。良かったら今後、活用してみて下さい。

全文を見る
すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.5

う~ん, どうやら全然理解してもらえなかったらしい.... main の dt と set の dt は全く別物なんです. だから, この状態ではせっかく set の中で malloc しても, その領域をプログラムの他のところで使う方法が存在しないんです. 例えば, #include <stdio.h> void set(int x) { x = 5; } int main() { int x = 0; set(x); printf("x = %d\n", x); return 0; } としても, 「x = 0」としか表示されません. でどうするかというと void set(int *x) { *x = 5; } とポインタを使って定義して, main の方も set(&x); と呼び出す. これは理解できてますか? これが理解できていれば, あなたのプログラムにおいて main で set(dt); と呼び出しているのがおかしいことに気付くはずです. ちなみに set の中の 2つ目の malloc は sizeof(int*) じゃなくて sizeof(int) ね.

yamasan0829
質問者

お礼

何度もありがとうございます。&の意味がようやく分かりました。 難しく難しく考えてしまって基本的なことを忘れていたようです。 二つ目のmallocの件、ありがとうございます。 見落としていました。

全文を見る
すると、全ての回答が全文表示されます。
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.4

★set()関数はポインタのポインタではないですね。 ・良くソースを見たらポインタのポインタに二次配列を確保しようとしていますね。  そしてそのポインタをset()、pt()に渡すのであれば『ポインタへのポインタ』のポインタを  渡します。つまり set( int ***dt ) となります。pt()関数は pt(int **dt)だけで良いです。 // 手直し版 int main( void ) {  int **dt;    set( &dt ); ←set()関数は『&』演算子が必要です。  pt( dt ); ←pt()関数はそのままで良い。 } // 引数宣言を見よ(1つ多くすること) void set(int ***dt ) {  char **alloc; ←これを宣言した方が分かりやすいでしょう。    alloc = (int**)malloc( sizeof(int*) * k );    for ( i = 0 ; i < k ; i++ ){   alloc[ i ] = (int*)malloc( sizeof(int*) * k );  }  *dt = alloc; ←注目 } これで問題は解決できますか? ちなみに過去質問に二次配列をmallocする方法が多数あります。 時間を掛けて検索すればもっと良いアドバイスが見つかります。 私も過去にいくつか回答を書いていますので…。

yamasan0829
質問者

お礼

なるほど・・ありがとうございます。とても勉強になります。 ポインタへのポインタ のポインタというのに全く気がつきませんでした。 ただ、私のソースはあまりよいソースではないようですね・・難しいですね。 一つ初歩的な質問なのですが、set関数の中で**allocを宣言していますが、 しない場合はどのように記述するべきなのでしょうか。 *dt = (int**)~~~ *dt[i] = (int*)~~ のようにしてもだめですよね。

全文を見る
すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

その x って関数はなんでしょうか? 変更したあとのプログラムを, 可能な限り出してもらえるとうれしいんだけど. ちなみに set の中の malloc でおかしいところがありますね.

yamasan0829
質問者

お礼

void set(int **dt); void pt(int **dt); int main(void){  int **dt;  set(dt);  pt(dt); } void set(int **dt){  dt = (int**)malloc(sizeof(int*) * k);  for(i = 0; i < k; i++){  dt[i] = (int*)malloc(sizeof(int*) * k); }  のように配列サイズの動的確保が目的 } void pt(int **dt){  二重forループ{   printf(dt[i][j]);  } } のように変更を加えた結果、コンパイル時のエラー、警告はなくなりました。

全文を見る
すると、全ての回答が全文表示されます。
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.2

★サンプル #include <stdio.h> // 関数 void sample( int **pos ) {  *pos += 5; } // メイン int main( void ) {  int array[ 10 ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };  int *p0 = (array + 0);  int *p5 = (array + 5);    sample( &p0 );    if ( p0 == p5 ){   printf( "一致\n" );  }  else{   printf( "不一致\n" );  }  return 0; } 上記のサンプルを活用してみて下さい。 sample()関数はポインタのポインタを受け取っています。 以上。

yamasan0829
質問者

お礼

サンプルまで用意していただきありがとうございます。 参考になります。 しかし、これを踏まえ色々なパターンを試してみましたがやはり実行できません。

全文を見る
すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

set に渡すところだけやるけど, 「ポインタのポインタ」と難しく考えるからいけないんです. int a; に対してこの a の値を別の関数 set で変えようとしたら set(&a); と渡すし, 受ける方は void set(int *a) などとなりますよね. これと同じです. 一般論として, T という型のデータを変えようとしたら, 受ける方では型 T* を持つ型が必要です. T = int なら T* = int * だし, T = int * なら T* = int **.

yamasan0829
質問者

お礼

ありがとうございます。 void x(int **dt){} x(int *dt); としてみました。 結果エラーはなくなりましたが、実行段階でエラーが出ます。 表示の部分の関数間の受け渡しが上手くいってないのかもしれません。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • ポインタの勉強中なのですが

    C言語の勉強中なのですが、ポインタのところで苦労しています。 次のような関数を作成し、main関数で実行したところ、sizeof(array)は4になりました。 main関数内で同じようにsizeof(array)を表させると配列全体のサイズが表示されますよね。 関数の仮引数として配列を書いても、実際には配列の先頭要素を指すポインタとして扱われるので 関数には&array[0]が渡され、関数は配列ひとつあたりのサイズを基に他の配列の要素のアドレスを 受け取るで合ってますよね? でもmain関数内ではsizeof(array)は配列全体のサイズを返すのに、関数内では配列ひとつあたりのサイズしか返さないのはどうしてなのでしょうか? int sum_array( int array[], int num ){ int i; int sum = 0; for( i = 0; i < num; i++ ){ sum += *(array+i); } printf("sum = %d\nsizeof(array)=%d\n",sum,sizeof(array)); return sum; }

  • ポインタのポインタとrealloc

    先程関数による動的確保について質問させていただき、ヒントを与えていただいたのですが、そこからまた疑問が生じました。 テストプログラムを作ったのですが、何やら動作がおかしいみたいです おかしい部分を抜き出したソースは次のとおりです int main() {  int **p;  int i;  p = (int **)malloc(sizeof(int *));  *p = (int *)malloc(sizeof(int));  p[0]=0;  for(i=1;i<10;i++){   *p = (int *)realloc(*p,sizeof(int)*(i+1));   *p[i] = i;  }  free(*p);  return 0; } 関数部として作りたい部分をメインにして抜き出しました。 このようにするとreallocがメモリ領域を拡張してくれなく(?)、*p[i] = i;の部分でエラー終了します。 ポインタのポインタではなく、ポインタを用いた時は正常に動作するのですが、何がまずいのでしょうか。 もし宜しければお願いいたします。 ちなみに私は学部4年生で、プログラムの使用は大学の研究用レベルです。

  • 配列ポインタの関数中のメモリ領域

    C初心者です。 関数中で配列ポインタを宣言する場合についての質問です。 たとえばDouble型の2次元のローカルな配列ポインタを用いる場合、 その配列要素数が100である場合は void 関数名(引数1,引数2,...){ int i; double *a[2]; for(i=0;i<2;i++){ a[i] = (double*)malloc(100*sizeof(double)); } for(i=0;i<2;i++){ free(a[i]); } } またこの値を引数1とする場合、引数1をoutとすると void 関数名(double *out,....) とし、 for(i=0;i<2;i++){ out[i] = a[i]; } とすればよいのでしょうか? もしこれがあっているとすると、つぎのような現象で困っています。 配列要素数を50000個ぐらいとし、複数の関数で、同様に mallocを用いて、配列ポインタのローカルでメモリ領域を確保しようとした場合、コンパイルは成功するのですが、その後実行すると、エラーが発生したというメッセージとともにコマンドウィンドが強制終了します。 コンパイラはVisual C++ EXpress Edition 2008です。 データサイズを小さくすると、エラーは起きません。 malloc関数で確保するメモリサイズは、関数の入力引数で定義された変数を用いて計算しており、データサイズに応じて変更されます。 よろしくお願いいたします。

  • ポインタ配列の動的確保

    ポインタの配列の動的確保について教えてください。 入力した数値をポインタ配列に入れるプログラムです。 下記のように書いてみました。(見づらくてごめんなさい) #include<stdio.h> #include<stdlib.h> #define kensu 3 main() { char abc[kensu+1]={'A','B','C','\0'}; char *ptr[kensu]; int i; printf("3つの整数を入力して下さい。\n"); for(i=0;i<kensu;i++){ ptr[i]=(char*)malloc(sizeof(char)*10); if(ptr[i]==NULL){ printf("メモリの取得に失敗しました"); exit(1); } printf("整数%c:",abc[i]); fgets(ptr[i],10,stdin); if(ptr[i][strlen(ptr[i])-1]=='\n') ptr[i][strlen(ptr[i])-1]='\0'; } for(i=0;i<kensu;i++) free(ptr[i]); } ちゃんと動いているようです。 しかし、ポインタ配列の動的確保をネットで調べてみると、ポインタのポインタ(?)を使って、下記のように2度mallocしています。 #include <stdio.h> #include <stdlib.h> #define N 3 int main(void) { char** arr; int i,j; arr = (char**)malloc(N * sizeof(char*)); /* ポインタ配列を確保 */ /* 配列の要素それぞれにつき、メモリ領域を確保 */ for(i=0;i<N;i++) arr[i] = (char*)malloc(N * sizeof(char));   ・・・ ポインタの配列を宣言して、配列の各要素に動的確保するのと ポインタのポインタを宣言し、ポインタ配列を動的確保して、再度配列の要素に動的確保するのとでは、何か違いがあるのでしょうか? ポインタのポインタを宣言し、ポインタ配列を確保する必要性が良く分かっていないのです。 ネット等で調べて見たのですが、理解力がないのかよく分かりませんでした。 どうか教えてください。

  • ポインタによる関数への配列渡し

    林晴比古さんの「新C言語入門」でC言語を勉強している初心者です。 現在ポインタの勉強をしています。色々教科書の文例等をポインタで書くとどうなるか試しております。 上書P200練習問題2に「配列の最大値を返す(その際配列の長さを渡す)」プログラムがあり、それをポインタで渡すプログラムに直してみました。 仮引数に「maxdata」を設定し、そのアドレスを関数側に渡し、関数側ではポインタとして受け取る(そうすれば関数側からはreturnで値を返す必要がない)、と考え、下記のように書いてみました。 #include <stdio.h> void max_of_array(int n[], int len, int *ans); int main(void) { int dt[6] = {50,20,80,30,10,40}; int maxdata; max_of_array(dt,6,&maxdata); printf("最大値=%d\n", maxdata); return 0; } void max_of_array(int n[], int len, int *ans) { int i; ans = &n[0]; for (i=1; i<len; i++){ if (*ans < n[i]) *ans = n[i]; } } しかしコンパイルすると、何故か「最大値=1」となってしまいます。(正しくは80です) 他にも色々試してみましたがうまくいかず、かなり考えてみたのですがどうしても分かりません。お分かりの方、どうすれば正しくなるのが教えてください、よろしくお願いします。

  • 関数とポインタについて

    #include <stdio.h> void test(int *p); int main() { int i; test(&i); printf("%d",i); return 0; } void test( int *p) { static int k; k = 10; p = &k; } このようなプログラムを作って、void test()のkの値をmain関数で受け取りたいのですが、どのようにすればよいのかわかりません。 どなたか教えていただけませんか?

  • C言語 ポインタ 関数

    キーボードから文字列”abcdefg”を入力し、main関数で配列aryに格納する。 main関数から配列aryの先頭アドレスを副関数に引き渡す。 副関数で配列aryの最後尾の要素の内容を';'に変更する。 main関数で配列aryの内容を表示する。 この問題が解けません... #include <stdio.h> int main (void) { char ary[]="abcdef"; int *p; int i,x; p=&ary[0]; func(&i); for (x=0;x<=7;x++){ printf("%s",ary[x]); void func (int i) if(i==\0) i=';' else i++ } return 0 } とりあえずこんな感じなんですけど、出来ませんでした...

  • 関数宣言

    3次元で領域を確保するプログラムをmalloc関数を用いて書きました。しかし、プログラムが長いので関数宣言をしなさいといわれたために、以下のプログラムを書きました。しかし、途中でつまづいてしまい、どのように関数を用いたり、関数を定義すれば良いのか混乱しています。初心者ですが、どうかお願いします。 /*ソース*/ #include<stdio.h> #include<stdlib.h> int main(){ double ***C; f3Malloc(C,.,.); //数値を代入(関数の使い方?) f3Free(C,.,.); } /*3次元配列(返し方?)*/ double*** f3Malloc(C,,){ int i,j,x,y,z; x = 2; y = 3; z = 4; C=(double***)malloc(sizeof(double**)*x*y*z); for(i=0;i<y;i++){ C[i]=(double**)malloc(sizeof(double*)*y*z); for(j=0;j<z;j++){ C[i][j]=(double*)malloc(sizeof(double)*z); } } } /*メモリの解放(返し方?)*/ void f3Free(C,.,.){ int i,j,x,y; x = 2; y = 3; for(i=0;i<x;i++){ for(j=0;j<y;j++){ free(C[i][j]); } free(C[i]); } free(C); }

  • 2次元配列とポインタの引数受け渡しについて

    2次元配列を関数に渡すときは、引数に渡す2次元配列と同じサイズを指定、もしくは2次元目のサイズのみ合わせて渡す方法がありますが、両方とも違うサイズで同じ関数を使いたいです。 最初は中身が同じで引数で受け取る2次元配列のサイズだけ、それぞれに合わせた引数を持つ関数を2つ作っていたのですが、なんだか冗長な気がしました。 そこで、2次元配列の先頭ポインタとサイズを受け取るようにすればいいのかと思い、テストとして次のプログラムを作成してみました。 #include <stdio.h> void func(unsigned char *a, int y, int x); int main(void) { unsigned char a[10][10]; func(a, 10, 10); printf("%d\n", a[7][4]); return 0; } void func(unsigned char *a, int y, int x) { int i, j; for (i = 0; i < y; i++) { for (j = 0; j < x; j++) { *(a + i*y + j) = i * j; } } } もちろんこれでも動くのですが、やはりこういう書き方はルールにはないので、コンパイルで警告が出ます。 a.c: In function ‘main’: a.c:10: warning: passing argument 1 of ‘func’ from incompatible pointer type a.c:4: note: expected ‘unsigned char *’ but argument is of type ‘unsigned char (*)[10]’ このような書き方はやはりやめたいいのでしょうか。 また、その際はサイズ別に関数を作るしかないのでしょうか。 他にいい方法があれば教えていただけると助かります。

  • C 関数とポインタ

    ポインタと関数がよく分かりません。 (日本語がおかしくてすみません(^_^;)) たとえば↓のようなプログラムで、 #include <stdio.h> void increase(int *i); int main(void) { int x = 3; increase(&x); printf("%d\n", x); return 0; } void increase(int *i) { (*i)++; } 結果は4になりますが、increase(&x)が&xとなっていて、 関数はvoid increase(int *i)でint *iになっているのですが、 これはvoid increase(int *i)はint型の「ポインタ」なので、 increase(&x)も&xと「アドレス」を渡さなければいけないということですか?? そして、void increase(int *i)内では、アドレス&xの指す値をインクリメント、という考えで良いのでしょうか?