• ベストアンサー

ポインタと {   } の関係とは

戻り値が配列(ポインタ)で返す関数を二つ作りif文で選択できるようにしたら 各要素の値がうまく表示されません。 最初に配列の各要素に自分で値を代入するか、ランダムに値を代入させるか決めて、代入させた配列を最後に表示させたいわけです。 #include <stdio.h> int RegistData(int *); int RandomData(int *, int); void main(){ int mous[6]; int select; printf("自分で表示入力するときは1を、コンピュータに任せるときは0を入力してください。"); scanf(" %d", &select); if(select == 0){  *mous = RandomData(mous); }else if(select == 1){ *mous = RegistData(mous); } for( i = 0 ; i < 6 ; i++) printf("%d ", mous[i]); } printf("\n"); } RandomData(int *mous) { //rand()関数でランダムに各要素に値を代入する処理をします。 return *mous; } RegistData(int *mous) { //自分で要素に値を代入する処理をします。 return *mous; } ちなみに、あらかじめ要素に値を入れておくと正常にうごきます。 int mous[6] = { 10, 15, 12, 23, 33, 42};//動作確認用表示

  • nVIDIA
  • お礼率46% (520/1121)

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

  • ベストアンサー
  • uu0v0uu
  • ベストアンサー率31% (17/54)
回答No.7

問題は主に2点のみのようです。 1.関数呼び出し部分 ■元 *mous = RandomData(mous); ここでは本来ならば以下のようにポインタを代入したいところです。 ■誤 mous = RandomData(mous); ところがmousは実体を持ってますので、 (結果的に問題はなくとも)戻りのポインタを代入してしまってはダメです。 入力時にすでにポインタを渡しているので 関数を抜けた時点でmousには値が入っているハズ、 次のように何も入れなくてOKです。 ■正 RandomData(mous); 2.関数内 確認だけなのですが関数内で mous[0]=1; mous[1]=3; ... こんな感じで値を入れてますよね? であれば問題なしです。 3.(おまけ)関数の戻り値 ■元 return *mous; 引数がint*になってるのですから、 配列を返したいのですよね、であれば、 ■正1 int* RandomData(int *mous) { return mous; } 一般的にはこうすべきです、が、1で戻り値を必要としなくなってますので、 ■正2 void RandomData(int *mous) { return; } こんなんでいいのではないでしょうか。 こういうのって難しいので頑張ってください。

nVIDIA
質問者

お礼

お返事遅れましたが、一通りできたのでご指導通り試してみました。 配列の場合は *mous = RandomData(mous); ではなくて RandomData(mous); でよかったのですね。そういえば値が戻ってきた時アドレスを新たに更新するのは変ですものね。大変勉強になりました。 それからもう一つ。 この関数あなたがおまけで言ったいたとおりに書いていました。 どうもアドバイスありがとうございます。さらに研究しよいプログラムが作れるようになりたいです。

その他の回答 (7)

  • rentahero
  • ベストアンサー率53% (182/342)
回答No.8

全くどうでもいいことではありますが、一点だけ、 > scanf() 関数の代わりに入力装置から安全に変数を > 代入する回避策はありますか? fgets(3)とsscanf(3)を使ってください。 この読み替えは常套手段です。

回答No.6

> scanf(" %d", &select); > 質問時の入力ミスでした。実際にはスペースは入れていません。 そうでしたか。ちなみに提示されているコードをよく調べたところ、他にも全角空白が入っているところがあったり、{} の対応が取れていなかったり、変数の宣言が無かったりしています。コードを提示されるときには、タイプしなおすのではなく、元のコードをコピー&ペーストされた方がよいと思います。ミスが少なくなりますし、何より楽です。  さて本題。  根本的な質問ですが、 > 各要素の値がうまく表示されません。 とは具体的にどううまく表示されないのでしょう? セットされているはずの値がまったくセットされていないのですか。それとも、一部のデータがおかしいのですか。 > ちなみに、あらかじめ要素に値を入れておくと正常にうごきます。 > int mous[6] = { 10, 15, 12, 23, 33, 42};//動作確認用表示  「正常にうごきます」とはどういう意味ですか。mous の値として、{10, 15, 12, 23, 33, 42} が表示される、という意味ですか。それとも RandomData(), RegistData() で正しく値がセットされ、それが表示される、という意味ですか。 > 変数 select にあらかじめ値を代入しておき > scanf("&d", &select); > を削除して、試してみました。 > そいしたら、正常に起動しました  これからすると、select に 0, 1 以外の値が select にセットされているように思うのですが、scanf の後に printf で select の値を確認してみてください。「先生からもscanf()関数は危険だから実際にはあまり使わないといっていたし。」とのことですが、scanf("%d", &select) は正当で何の問題も無いはずです。  提示されたコードに少し手を入れたものです(文法エラーになった箇所を修正し、RandomData() と RegistData() の中身を書いた)。これをコンパイル、実行したところ、何の問題も無く、select への入力値 0, 1 に従って、RandomData(), RegistData() でセットした値が表示されました。怪しい *mous = ... という表記も RandomData(), RegistData() の中で、mous の値を変えていない限り問題は無いようです。 #include <stdio.h> int RegistData(int *); int RandomData(int *); void main() { int mous[6]; int select; int i; printf ("自分で表示入力するときは1を、コンピュータに任せるときは0を入力してください。"); scanf("%d", &select); if (select == 0) { *mous = RandomData(mous); } else if (select == 1) { *mous = RegistData(mous); } for (i = 0; i < 6; i++) { printf("%d ", mous[i]); } printf("\n"); } RandomData(int *mous) { //rand()関数でランダムに各要素に値を代入する処理をします。 int i; for (i = 0; i < 6; i++) { mous[i] = i; } return *mous; } RegistData(int *mous) { //自分で要素に値を代入する処理をします。 int i; for (i = 0; i < 6; i++) { mous[i] = i + 10; } return *mous; }

nVIDIA
質問者

お礼

これはお礼ではありません。補足に誤りがあったのでお礼に書きます。 main関数に DataChek(hoge); と書きましたが、誤りでした。 正しくは以下の通りです。 DataInput(&hoge); まちがいだからですみませんでした。

nVIDIA
質問者

補足

このScanf()関数ですが、別のマシンでテストしてみたら問題なく動きました。ただ、このscanf()関数。同じ同級生でも入力したら暴走したとかなどのトラブルがチビチビ発生しており、少し進んだ人は「普通はつかわないでしょ。」と答えるくらいです。 scanf()関数は現在のところ、C言語の基礎を学習する時に使うまでにとどめています。 私は、一つのプログラムを作りなさいというときはあらかじめ入力装置から値を入力する関数を作っておき各変数などに値を代入しています。 #include <stdio.h> #include <stdlib.h> int DataChek(); void DataInput(int *); void main() { int hoge; printf("値を入力してください"); DataChek(hoge); printf("いま入力した値は %d です\n", hoge); } //////////////////////////////////////////////////////////////////////////////////// //データチェック処理 入力:なし 出力:入力文字列 int DataChek() { char buffer[100]; int out; fgets(buffer, 100, stdin); sscanf(buffer, "%d", &out); return out; } //////////////////////////////////////////////////////////////////////////////////// //データ入力処理 入力:入力文字列 出力:なし void DataInput(int *buffer) { *buffer = DataChek(); } //////////////////////////////////////////////////////////////////////////////////// 以上な方法をとっています。この仕組みは別のサイトで紹介されていたのを自分で調べて省略して使っています。

  • ency
  • ベストアンサー率39% (93/238)
回答No.5

すでに何名かの方が回答されているように、ご質問に書かれていない処理の部分に問題がありそうに思います。 まず、配列とポインタの関係について正しく理解することが大切です。 「配列名がポインタと同等」というのは、ある意味で正しいですが、配列を返しているつもりで「return *mous」と書いているようですので、その捉え方を間違っているように思います。 配列は、コンパイラによってその「先頭要素を指すポインタ」に読み替えられます。 ここで注意が必要なのは、「配列」が「配列を指すポインタ」に読み替えられるわけではありません。 「配列」は「配列の先頭要素を指すポインタ」に読み替えられるのです。 nVIDIA さんは、この部分を勘違いなされているように思いましたが、いかがでしょうか。 # もし、そうでなかった場合は、すみません。。。 つまり、「int mous[6];」と定義した場合、以下のそれぞれが同じことを意味するようになります。 mous == &mous[0] // mous は配列の先頭要素 (mous[0]) を指すポインタに読み替えられる。 *mous == mous[0] // *mous は、結局配列の先頭要素 (mous[0]) のこと。 (mous + 1) == &mous[1] // (mous + 1) は配列の要素1個分進めた要素 (mous[1]) を指すポインタ。 *(mous + 1) == mous[1] // *(mous + 1) は結局 mous[1] のこと。 …以降同様です。 そうすると、RegsitData() や RandomData() で、引数としてわたってきた「int *mous」に対して「return *mous;」としていることの無意味さが、お分かりになりませんか? # この部分は、よく考えてみてください。 変数 select の設定処理を削除するとうまく動作した、とのことですが、それは今回発生している問題の本質ではない気がします。 # 特に、RandomData() でも scanf() での値の入力をしていると思われますので # 入力ストリームがおかしくなっている可能性があると思います。 長々と書いてしまいましたが、ご参考になりますでしょうか。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.4

RegistData RandomData で配列をポインタ渡しで渡して値を(直接に)セットするなら特別返値は必要ないと思います。 >return *mous; で何を返しているのか、それを何に利用しようとするのか考える必要があります。 もしポインタを返したいのであれば return mous; のようにします。 また、 >int RandomData(int *, int); では、プロトタイプと実際に定義されている引数の数が異なります。

nVIDIA
質問者

補足

RandomData関数では、引数として空の配列が入ります。そして要素一つ一つにrand()関数で数値を代入してゆき、各要素に代入されたらその配列を返す仕組みです。 配列名はポインタと同じ扱いだそうですのでこのような形にしました。

回答No.3

scanf(" %d", &select); で %d の前の空白が全角の空白になっています。そのため、select に入力した値がセットされず、ごみが入った状態になります。selcet が 0 でも 1 でも無いため、配列 mous の中身もごみのままになっているわけです。  全角の空白を削除してください。

nVIDIA
質問者

補足

scanf(" %d", &select); 質問時の入力ミスでした。実際にはスペースは入れていません。

回答No.2

RegistData()とRandomData()関数内の処理が間違っていなければこれでも正しい結果が得られると思いますが,ポインタの使い方を勘違いされているようです。 *mous = RandomData(mous); この行は,関数RandomData()のint型の戻り値をmous[0]に代入しています。関数RandomData()ではreturn *mous;によってmous[0]を戻り値としていますので,結果として mous[0]=mous[0]; と同じ働きをしますので,正しい結果が得られると思います。 注意するべきなのは,mous配列はmain関数のローカル配列変数であり変更することはできないのですが,RegistData()とRandomData()関数に渡された時点で(コンパイラによっては)ただのポインタ変数として扱われますので,ポインタの変更ができてしまうということです。 もしこれらの関数内でポインタの変更をして,値の格納場所を変えたつもりになっていても,ポインタ*mousはこれらの関数内のローカル変数で,かつ,前述のとおり戻り値としてはポインタではなく配列の先頭の値を戻していますので,main関数内では自分で確保したmous配列を参照します。 関数宣言を int *RegistData(int *); int *RandomData(int *, int); として,そえぞれの関数内の戻り値を return mous; としてポインタを戻したとしても,main関数内で mous = RandomData(mous); とした時点で定数への代入となり,エラーが出ます。 推測しかできませんが,あらかじめ要素に値を入れた場合には,main関数内でのみ値が完結しており,他の関数内でポインタをいじっても(たまたま)影響なく表示されているように見えます。

nVIDIA
質問者

補足

変数 select にあらかじめ値を代入しておき scanf("&d", &select); を削除して、試してみました。 そいしたら、正常に起動しました。どうやら、ここに原因があるようです。先生からもscanf()関数は危険だから実際にはあまり使わないといっていたし。 じゃあ scanf() 関数の代わりに入力装置から安全に変数を代入する回避策はありますか?

  • shkwta
  • ベストアンサー率52% (966/1825)
回答No.1

(1)ご質問に書かれていない、RandomData と RegistDataの中身に問題がありそうです。 (2)それと関連して、RandomData と RegistDataがintを返していることと、それを *mous に代入していることは、ご希望の処理に役立たない無意味な動作に思います。

関連する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; }

  • 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 } とりあえずこんな感じなんですけど、出来ませんでした...

  • ポインタいついて教えてください

    ポインタがわかりません。 教えてください。 下の二つは、共に「100」を表記すると思いますが、 どこがどのように違うのですか。 また、f1()という関数をつくって、ここで scanfを使って、5つぐらい値を代入させて、 他の関数でこの値を使おうと思っています。 この場合下のどちらを使うのが、よろしいのでしょうか。 よろしくお願いします #include <stdio.h> int main(void) { int *p, q; q = 100; /* q に100を代入 */ p = &q; /* p にq のアドレスを割り当てる */ printf("%d", *p); return 0; } #include <stdio.h> int main(void) { int *p, q; p = &q; /* q のアドレスを得る */ *p = 100; /* ポインタを使ってq に値を代入する */ printf("%d", q); return 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; }

  • ポインタ

    文字列"apple", "orange", "strawberry"へのポインタをポインタ配列の各要素に代入した後,その文字列の文字を逆順に表示するようにプログラムを考えているのですが、 while文の中のjはそれぞれについて考える必要がありますか? ポインタを使って文字数を数得られそうですが出来ませんでした。 [実行例] ポインタ配列[0]の文字列の逆はelppaです. ポインタ配列[1]の文字列の逆はegnaroです. ポインタ配列[2]の文字列の逆はyrrebwartsです. #include<stdio.h> #define COUNT 3 int main(void) {   char * words[COUNT] = {"apple", "orange", "strawberry"};   int i, j;   for(i = 0; i < COUNT; i++) {    j =  ?  ;    printf("ポインタ配列[%d]の文字列の逆は", i);    while(   ?   ) {     printf("%c", *(words[i] + j));     j--;    }    printf("です.\n");   }   return 0; }

  • ポインタへの代入

    int main() {int *i =0xffffffff; printf("&p...%p",&p); return 0;} としてiにffffffffのアドレスを代入しても別のアドレスが表示されます。なぜでしょうか。

  • インクリメントしてくれません

    配列mousの各要素を配列tousと照らし合わせ、マッチしたら変数countにインクリメントし、何回マッチングしたかを返す関数を作りました。 でも、なぜか1回しかインクリメントしてくれません。 確認のため試しにcount++部分をputf("テスト表示")に置き換えた場合マッチングした回数だけ「テスト表示」表示されました。 じゃあなぜ、変数countは一回しかインクリメントされないのでしょうか? #include <stdio.h> int DataMatch(int *, int *); void main() { int mous[6] = { 1, 15, 12, 23, 33, 42}; int tous[7] = {10, 15, 19, 23, 33, 42, 11}; int test; test = DataMatch(mous, tous); printf("%d%\n", test); } ////////////////////////////////////////////////// int DataMatch(int *buffer1, int *buffer2) { int i, j, count; for(i = 0; i < 6 ; i++ ){ for(count = 0, j = 0; j < 6; j++){ if(buffer1[i] == buffer2[j]){ count++;//インクリメントしてくれない! break; } } } return count; }

  • できているとは、思うのですが。ポインタの配列を

    コンパイラではちゃんと動いてます。 1 2 3 0 1 2 3 という具合です。 気になるのは、printarrayの部分が正しいのか、ちょっと悩んでいます 問題としては main関数では0の値を読み込むまで最大99(MAX-1)個の値を配列 xに読み込んでいる。引数のポインタからの値を、値が0になるまで すべて1行に1つづつ画面に出力する関数printarray()を作成し、 プログラムを完成せよ。 引数はアドレスとして受け取る事。(配列としてでなく) フォーマットは、 "%d¥n" とする。(余計な出力はしない事。) (0は出力しない。) main内部を変更してはならない。 以下がソースです。 ご指摘よろしくお願いします。 #include <stdio.h> #define MAX 5 void printarray(int *); int main() { int x[MAX], i; int *p; x[MAX-1] = 0; for (i = 0, p = x; i < MAX-1; ++i, ++p) { scanf("%d", p); if (*p == 0) { break; } } printarray(x); return 0; } void printarray(int *a) { int i,*p; for(i = 0, p = a; i < MAX-1; ++i,++p) { if(*p == 0){ // continue; break; }else{ printf("%d\n", *(a+i)); } } }

  • ポインタ配列

    配列をポインタでとって、配列要素を足していこうと思ったのですが、 #include <stdio.h> int main (void) { int p[11]={11,23,43,66,54,67,51,88,22,43,-1}; int *e=p; int x=0; int i=0; while( *e!=-1 ) { x + = ( * (e+i) ); i++; } printf("%d\n",x); return 0; } x = ( * ( e+i ) ); ↑この部分がなぜだめなのか理解できません どなたか教えてくださるとありがたいです

  • ポインタに ~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を入れるということは、ヌルポインタであって、ポインタとして無効なんですよ」のようなこと。)