• ベストアンサー

ポインタお手上げです。

#include <stdio.h> main() { void original(int[], int *[], int *[], int *[]) ; int i, origin[10]; int m2[10],m3[10],m5[10]; for(i = 0; i < 10; i++){ scanf("%d", &origin[i]); } original(origin, &m2[], &m3[], &m5[]); printf("2の倍数:"); for(i = 0; i < 10; i++){ printf("%2d ,", m2[i]); } printf("\n"); printf("3の倍数:"); for(i = 0; i < 10; i++){ printf("%2d ,", m3[i]); } printf("\n"); printf("5の倍数:"); for(i = 0; i < 10; i++){ printf("%2d ,", m5[i]); } printf("\n"); return 0; } void original(int origin[], int *multiple_2[], int *multiple_3[], int *multiple_5[]) { int i, m2 = 0, m3 = 0, m5 = 0; for(i = 0; i < 10; i++){ if(origin[i] % 2 == 0){ *multiple_2[m2] = origin[i]; m2++; } if(origin[i] % 3 == 0){ *multiple_3[m3] = origin[i]; m3++; } if(origin[i] % 5 == 0){ *multiple_5[m5] = origin[i]; m5++; } } } 上のプログラムをコンパイルし実行するとセグメントエラーがでてしまいます。どこがわるいんでしょうか・・・。上のプログラムは、外部入力から10個の数字をoriginに格納しそれをそれぞれ2の倍数、3の倍数、5の倍数をあらわすポインタにそれぞれを格納していき、最後にそれを表示するプログラムなんですが・・・。いまいち配列を持ったポインタを使い、なおかつ引数として使うやり方がうまくわからないからこんなエラーが出るような気もします・・・。どなたか初心者でもわかるようなアドバイスお願いします!

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

  • ベストアンサー
  • panda0000
  • ベストアンサー率35% (59/165)
回答No.4

No.3の者です。 ポインタはアドレスなので、 int origin[10], *op=origin; のところで、intが4バイトの場合、 例えば origin[10]がメモリのアドレスFFA0~FFC8までにとられ、 opはポインタ変数で、origin(*origin[0])のアドレスFFA0が入ります。 (配列名originは、その配列の最初のポインタ) >m2p = m2; m3p = m3, m5p = m5; >↑の行は何故必要なんでしょうか。実際この行がなしでコンパイル >したんですけど上手くいきません。どうしてでしょうか・・・。 ループの中の、 *m2p++ = *m3p++ = *m5p++ = 0; の行で、0を入力していくために、それぞれのポインタをインクリメントしています。 (ループ終了時には、例えばm2pは、存在しないm2[10]のアドレスを示しています) 関数に渡す際には、m2[0]から埋めていってもらうために、 また、倍数を表示させる際は、またm2[0]から順に見ていく必要があるので、 一度m2pにm2を代入し、m2pをm2[0]のアドレスに戻さなくてはいけません。

Carnofarzy
質問者

お礼

なるほど!!大変よく分かりました!!ということは、 *m2p++ = *m3p++ = *m5p++ = 0; の行を *(m2p++) = *(m3p++) = *(m5p++) = 0;としてforループを一回分減らせば、先頭のアドレスに変更が無いので m2p = m2; m3p = m3, m5p = m5; は、記述しなくてもいいってことにもなりますよね? 二度も回答してくださってほんとうにありがとうございました!!

その他の回答 (4)

回答No.5

No.2の者です。 じっくりプログラムを読まずに回答してしてしまい、ポイントがズレてしまっていたみたいですね。すみません。 ところで、じっくりとあなたが書かれたプログラムを見ますと理解に苦しむところが1点あります。 (1)関数originalの引数。    第1引数のみ整数の配列(int[])で、後が整数の配列のポインタ(int *[])    となっている点。    どうして第1引数のみが、整数の配列なのでしょうか?全て整数の配列とした方が判りやすいしよいのでは? あなたが書かれたプログラム中の矛盾点(BUG)は下記の点では? (1)関数originalの第2仮引数以降の使用方法 第2仮引数以降は整数の配列のポインタとして宣言されているので、下記のようにするべきでは、  *multiple_2[m2] → multiple_2[m2] あなたが書かれたプログラムでは、 *multiple_2[m2] →*(multiple_2[m2])となり、 配列multiple_2からm2番目の配列(配列multiple_2のm2番目の要素ではありません)の第1要素を示すことになり、これは多分不定になっているので不正なところに書き込みをすることとなりセグメントエラーがでてしまているのではないかと思われます。

Carnofarzy
質問者

お礼

回答ありがとうございます。 確かに、全て配列としたほうがわかりやすかったですね・・・。別のプログラミングを参考にしながらやっているとこのようになってしまいました。 二番目のご指摘につきましては、確かにポインタの扱い方がおかしいですね。言われて読み返してみると間違いに気付きました。どうもご指摘ありがとうございました。

  • panda0000
  • ベストアンサー率35% (59/165)
回答No.3

紛らわしくしてしまうかもしれないので申し訳ないのですが、 せっかくポインタの勉強をするのでしたら、配列の[]を使わないで組む練習をしてみるのもいいかと思います。 少し書き換えてみましたので(短時間なので汚いですが)、 もしよろしければ読み解いていただくと勉強になるかと思います。 int main() { void original(int *, int *, int *, int *) ; int i, origin[10], *op=origin; int m2[10], m3[10], m5[10], *m2p=m2, *m3p=m3, *m5p=m5; for(i=0; i<10;i++) { scanf(" %d", op++); *m2p++ = *m3p++ = *m5p++ = 0; } m2p = m2; m3p = m3, m5p = m5; original(origin, m2, m3, m5); printf("2の倍数:"); while (*m2p) { printf("%2d ,", *m2p++); } printf("\n"); printf("3の倍数:"); while (*m3p) { printf("%2d ,", *m3p++); } printf("\n"); printf("5の倍数:"); while (*m5p) { printf("%2d ,", *m5p++); } printf("\n"); return 0; } void original(int *origin, int *multiple_2, int *multiple_3, int *multiple_5) { int i, m2 = 0, m3 = 0, m5 = 0; for (i = 0; i < 10; i++, origin++) { if (*origin % 2 == 0){ *multiple_2++ = *origin; } if(*origin % 3 == 0){ *multiple_3++ = *origin; } if(*origin % 5 == 0){ *multiple_5 = *origin; } } }

Carnofarzy
質問者

お礼

返信ありがとうございます。 配列を使わずにやるとすごいコンパクトになりますね。大変勉強になりました。 すこしわからないとこがあるんですが m2p = m2; m3p = m3, m5p = m5; ↑の行は何故必要なんでしょうか。実際この行がなしでコンパイルしたんですけど上手くいきません。どうしてでしょうか・・・。

回答No.2

配列名は確かポインタ定数のはずですので下記のところが 間違っているのでは? 誤 original(origin, &m2[], &m3[], &m5[]); 正 original(origin, m2[], m3[], m5[]); 後、うろ覚え(幾分忘却の彼方)なので、確認願いますが、 *と[]の優先順位はどうでしたか? *multiple[] は、(*multiple)[] or *(multiple[]) のどちらでしたっけ? (前者は配列のポインタ、後者は配列のポインタのポインタだったようナ!)

Carnofarzy
質問者

お礼

返信ありがとうございます。 正のほうに変えてみたところやはりエラーが出てしまいます。 優先順位は・・・おそらく[]のほうがさきだったような・・・

  • nitscape
  • ベストアンサー率30% (275/909)
回答No.1

ポインタ以外は理解できているようですね。 「ポインタ」という言葉に惑わされず、単なる「アドレス(メモリ上の位置を示す数字)」ということを頭に常に置くと理解しやすいと思います。ある関数にアドレスを渡せば、その関数内ではそのアドレスに対して読み書きすることができます。そうするとそのアドレスに書き込まれた値はプログラム上のどの部分から読み出すことができる...という感じです。 TRACEはprintfに直してください。またscanfも消したのでご自分で入れてください。 #include <stdio.h> void original(const int* origin,int* multiple_2,int* multiple_3,int* multiple_5) { int i, m2 = 0, m3 = 0, m5 = 0; for(i = 0; i < 10; i++){ if(origin[i] % 2 == 0) { multiple_2[m2] = origin[i]; m2++; } if(origin[i] % 3 == 0){ multiple_3[m3] = origin[i]; m3++; } if(origin[i] % 5 == 0){ multiple_5[m5] = origin[i]; m5++; } } } main() { int i, origin[10]; int m2[10],m3[10],m5[10]; for(i = 0; i < 10; i++) { origin[i] = i; m2[i] = 0; m3[i] = 0; m5[i] = 0; } original((int*)origin,(int*)m2,(int*)m3,(int*)m5); printf("2の倍数:"); for(i = 0; i < 10; i++){ TRACE("%2d ,", m2[i]); } TRACE("\n"); printf("3の倍数:"); for(i = 0; i < 10; i++){ TRACE("%2d ,", m3[i]); } TRACE("\n"); printf("5の倍数:"); for(i = 0; i < 10; i++){ TRACE("%2d ,", m5[i]); } TRACE("\n"); return 0; }

Carnofarzy
質問者

お礼

返信ありがとうございます。 とてもよくわかりました。 ただ一つこの行がいまいち理解できないのですが・・・ original((int*)origin,(int*)m2,(int*)m3,(int*)m5); 特に (int*)の部分がわからないのですが・・・。

関連するQ&A

  • ポインタを使ったプログラム

    Cを勉強し始めて3ヶ月ほどの初心者です。 ポインタの概念がどうしても理解できず、つまずいています。以下のような簡単な問題があります。 「関数void func( int *n1, int *n2, int *n3 )を作り、1以上50以下の整数で,2または3または7で割り切れない整数を画面に表示するプログラムを作れ。なお、第1,第2,第3引数のアドレスの中身は、それぞれ2,3,7で割ったときのあまりとする。」 2で割ったときのあまり、3で割ったときのあまり、7で割ったときのあまりの積が0でないときに表示していけばよい、という考えから、以下のようなプログラムを作ってみました。 #include<stdio.h> void func(int *n1, int *n2, int *n3); int main(void) { int m,*m1,*m2,*m3; m1 = &m; m2 = &m; m3 = &m; for(m=1;m<=50;m++){ func(m1,m2,m3); if(*m1 * *m2 * *m3 != 0){ printf("%d ",*m1 * *m2 * *m3); } } } void func(int *n1, int *n2, int *n3) { *n1 = *n1 % 2; *n2 = *n2 % 3; *n3 = *n3 % 7; } ただ、本質がわかっていないまま作っているので、明らかに間違っていると思います。ポインタを使わなければ作れると思うのですが。 どこが間違っているのか、正しいプログラムは何か、初心者にもわかるように教えていただければありがたいです。

  • ポインタに ~0を入れること

    見かけたCのプログラムで、 ポインタに~0を代入するものを見ました。 そのプログラムをそのまま載せるのはわかりにくいので、 代わりに以下のプログラムを作って実行しました。 #include <stdio.h> int main(void) { char *pa[3]; int i; pa[0]=0; pa[1]=~0; pa[2]="Hello"; printf("sizeof(char*)=%d\n", sizeof(char*)); for(i=0; i<=2; i++) { if(pa[i]==NULL) printf("pa[%d] はNULLです。\n", i); if(pa[i]==(char*)0xFFFFFFFF) printf("pa[%d]は全ビット1です。\n", i); if(pa[i]==~0) printf("pa[%d]は~0です。\n", i); } return 0; } 結果 sizeof(char*)=4 pa[0] はNULLです。 pa[1]は全ビット1です。 pa[1]は~0です。 このプログラムはコンパイル時にエラーも警告も出ず、 動作も意図したとおりです。 pa[1]に入っている ~0 は、int型の定数なのでしょうか。 それならば、 pa[1]=~0; という代入や if(pa[i]==~0) という比較は 左辺はchar*型で右辺はconst int型であって型が異なりますが、 問題ないのでしょうか。 ~0は0の否定なので、全ビットは1なのでしょうけど、 int型(の定数)だと思います。 ~0というのは何か特別な値なのでしょうか。 ポインタに~0を入れるというのは、意味があるのでしょうか。 (例えば、「ポインタに0を入れるということは、ヌルポインタであって、ポインタとして無効なんですよ」のようなこと。)

  • ポインタのポインタ

    こんにちは。 C言語の「ポインタのポインタ」の学習中なのですが、以下のプラグラムがエラーが出てしまします。 if文が間違っていると思うのですが、具体的に何がどう間違っているのがわかりません。 ご教示お願いいたします! #include<stdio.h> int main(void) { int date = 300; int *pdate = NULL; int **ppdate = NULL; printf("dateの値は%d<\n", date); pdate = &date; printf("*pdateの値は%d<\n", *pdate); if(**ppdate = NULL){ printf("**ppdateには何も与えられていません。\n"); } else{ return 0; } ppdate = &pdate; if(**ppdate == 300){ printf("**ppdateの値は%dになりました。正常です。\n", **ppdate); } /*強制終了を避けるためのプログラム*/ int i; scanf("%d", &i); return 0; }

  • ポインタのエラー?

    配列とポインタを使って多数桁の加算をするプログラムを作ったのですが、演算結果を表示した後にエラーが出てしまいます。初心者なので書式もばらばらで読みにくいと思いますが、お願いします。 #include <stdio.h> #include <stdlib.h> #define N 10 void main() { int *a,*b,*result,carry,i; a=(int *)calloc(N+1,sizeof(int)); b=(int *)calloc(N+1,sizeof(int)); result=(int *)calloc(N+1,sizeof(int)); /*配列aへの読み込み*/ for(i=1;i<N+1;i++) scanf("%d",&*(a+i)); *a=0; printf("入力された数値:"); for(i=1;i<N+1;i++) printf("%d",*(a+i)); printf("\n"); /*配列bへの読み込み*/ for(i=1;i<N+1;i++) scanf("%d",&*(b+i)); *b=0; printf("入力された数値:"); for(i=1;i<N+1;i++) printf("%d",*(b+i)); printf("\n"); /*配列resultの初期化*/ for(i=0;i<N+1;i++) *(result+i)=0; carry=0; /*result=a+bの演算*/ for(i=(N+1);i>=0;i--){ *(result+i)=*(a+i)+*(b+i)+carry; if(*(result+i)>=10){ *(result+i)-=10; carry=1; } else carry=0; } /*演算結果の表示*/ printf("和:"); for(i=0;i<N+1;i++) printf("%d",*(result+i)); printf("\n"); /*メモリ領域の解放*/ free(a); free(b); free(result); }

  • 関数化について

    何度も質問しているんですがまた行き詰ってしまいました 以前解答をいただき自分なりに進めていき以下のことができるようになりました 1、多項式の係数を入力し、多項式(A)をつくる。 2、それを微分したもの(A’)で割る。→A÷A’=商・・・余りB 3、出てきた余り(B)を割る数、ひとつ前の作業で割る数だったもの(A’)を割られる数にする。 4、割る数(B)の最高次の係数の2乗をしたもの(a^2)を割られる数(A’)にかける。(擬除法) 5、割り算を行う。→(a^2)×A’÷B 6、余りが0になるまで3~5を繰り返す。(0にならなければ終わり) 7、割り切れたときの割る数がAとA’の最大公約数Dとなる(正確には最大公因数?) とここまでできるようになりました。 で、次にさらにまた 8、A÷D=E 9、DとEでユークリッドの互除法により最大公約数Gを求める 10、E÷G=P→PがAのi次の平方因子 11DをAとしDが無平方になるまで1~10を繰り返す。 といったことをやらなければいけないんですが、 いい加減関数を使わないと長すぎるので同じ作業を簡略化するため関数化することにしました。 で、微分のプログラムは関数化できたんですが、ユークリッドの互除法のプログラムが難しくて関数化できません。 わかる方お願いしますm(_ _)m 以下プログラム #include <stdio.h> #include <math.h> int main(void){ int m,m2,i,j,k,l,n,p,q; int a[1000],b[1000],c[1000],d[1000],e[1000]; puts("何次の多項式ですか?"); printf("何次:"); scanf("%d",&m); puts("多項式の係数を入力してください。"); for(i=m;i>=0;i--){ scanf("%d",&a[i]); //e[i]=a[i]; //printf("e[i]=%d\n",e[i]); } derivative(&m,a,&m2,b); printf("微分された多項式は:"); for(i=m2;i>=0;i--){ printf("%dx^%d+ ",b[i],i); } printf("\n\n"); q = 1; l = 0; while(q == 1){ printf("割られる数は:"); for(i=m;i>=0;i--){ a[i]=a[i]*(b[m2]*b[m2]); printf("%dx^%d + ",a[i],i); } q = 0; printf("\n上のは割る数の最高の次数の係数の2乗をかけたもの:b[m2]=%d\n",b[m2]); printf("--\n"); printf("%d回目の商は\n",l+1); for(k=m-m2;k>=0;k--){ c[k] = a[m - (m - m2 - k)] / b[m2]; printf("%dx^%d + ",c[k],k);//商の表示 j = m2; for(i = m - (m - m2 - k);i>= m - (m - m2 - k) - m2 ;i--){ d[i]=a[i]-c[k]*b[j]; a[i] = d[i]; j = j - 1; } } printf("\n"); for (k = m2;k >=0 ;k--){ a[k] = b[k]; } printf("余り:"); for (k = m2-(m-m2);k >=0 ;k--){ b[k] = d[k]; printf("%dx^%d + ",b[k],k); if (d[k] != 0){ q = 1; } } for (k = 0;k <= 1000;k++){ d[k] = 0; } printf("q:%d\n",q); p = m2 - 1; m = m2; m2 = p; l = l + 1; printf("\n"); while(b[m2] == 0){ m2 = m2 - 1; } if (m2 <= 0){ break; } } if (q == 0){ printf("割り切れた"); }else{ printf("割り切れなかった"); } return(0); } int derivative(int *m, int a[],int *m2, int b[]) { int i; for(i=*m;i>0;i--){ b[i-1]=i*a[i]; } *m2=*m-1; return(0); }

  • ポインターを使った並べ替え

    ポインタを用いてソートを行うプログラムを作成しています しかし、関数部分が悪いのか、上手く作動されません よろしければ、アドバイスをいただけると嬉しいです #include <stdio.h> #define MAX 10 #define RandMax 1000 void select_sort(int *a, int n){ int *i, *min, *last, t; last=a+n; for(i=a; i<last; i++){ min=a; for(i=a+1; i<last; i++) if(*i<*min) min=i; t=*min; *min=*i; *i=t; } } main(){ int *a, i; a=(int*)calloc(MAX,sizeof(int)); for(i=0; i<MAX; i++) a[i]=rand()%RandMax; select_sort(a, MAX); printf("data size=%d \n", MAX); for(i=0; i<MAX; i++){ printf("%5d", a[i]); if(i%10==9) printf("\n"); } } 以上が私の作成したプログラムです よろしくお願いします

  • ポインタのポインタ

    #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char **argv){ int i; if(argc != 2) { fprintf(stderr, "Usage: %s vector\n\tEx: %s 11110000\n", argv[0], argv[0]); return 1; } for(i=0;i<8;i++){ if(**argv == '0'){ printf("%d\n",i); } else{ printf("A%d\n",i); } argv++; } return 0; } コンパイルして./a.exe 10010011などと入力しても A0 A1 Segmentation Faultとなります。 どうすれば、 A1 0 ・・・省略 for文で回した8回分、出力が可能になるのか教えてください。 初歩的な質問ですいません。

  • ポインタと配列 助けてください

    #include <stdio.h> int main(void) { int a[5] = {1, 2, 3, 4, 0}; int i, *ptr; ptr = ######; while (*ptr != 0){ ######; ######; }      for (i = 0; i < 5; i++) printf("a[%d]=%2d &a[%d]=%p\n", i, #####,i, #####); putchar('\n'); ptr = ######; for (i = 0; i < 5; i++){ printf("ptr値 =%d ptrアドレス =%p \n", ####, ####); ####; } printf("\n"); return (0); } 一次元配列a[]の一番目の要素以外を0にするプログラム(ただし、最後の要素は0)を作成したいのですが、#の部分に何をあてはめたらいいかわかりません。 助けてください。

  • 10個で改行したいのですが

    int _tmain(int argc, _TCHAR* argv[]) { int i,n,j,w,m,; printf("素数は\n"); n=0; for(i=1; i<=2000; i++){ n=n+i; w=0; for(j=1; j<=i ;j++){ m=i%j; if(m==0){ w=w+1; } } if(w==2){ printf("%d、",i); } } return 0; } このプログラムは2000までの素数を出力するプログラムです。この結果の素数10個ずつで改行したいのですが、どうすればよいでしょうか? お願いします。

  • 因数分解プログラム(C言語)について(3)

    つづきです /*求めた最大公約数で約分*/ if(*flag == 1){ *d = *m1 / *i; *e = *n1 / *i; } else{ printf("約分できません。\n"); *d = *m1; *e = *n1; } return 0; } int yakubun2(int *m2,int *n2,int *min2,int *flag,int *i,int *f,int *g) { /*最大公約数を見つける*/ if(*m2 < *n2){ *min2 = *m2; } else{ *min2 = *n2; } *flag = 0; for(*i = min2; *i > 0; *i--){ if(*m2 % *i == 0){ if(*n2 % *i == 0){ *flag = 1; break; } } } /*求めた最大公約数で約分*/ if(*flag == 1){ *f = *m2 / *i; *g = *n2 / *i; } else{ printf("約分できません。\n"); *f = *m2; *g = *n2; } return 0; } /*因数分解の結果を表示*/ int output(int *d,int *e,int *f,int *g) { printf("(%dχ-%d)(%dχ-%d)",*d,*e,*f,*g); return 0; } 関連URL:http://www.okweb.ne.jp/kotaeru.php3?q=474597

専門家に質問してみよう