• ベストアンサー

警告 ”値が割り当てられていないローカルな変数~”について

以下のコード1では、”値が割り当てられていないローカルな変数 'key' に対して参照が行われました。”という警告が出ますが、コード2では出ません。 コード2でも値が割り当てられていないと思うのですが、どうして警告が出ないのでしょうか? お分かりの方、お教えくだい。 あと、かなり省略してしまったので、意味の無いコードになってしまいましたが、この2つのコードでkeyの意味合いはどう違うのでしょうか? よろしくお願いいたします。 <コード1> int in_dt() { int *key; scanf( "%d", key );///ここで警告が出る return 1; } int main( void ) { int code; code = in_dt( ); return 0; } <コード2> int in_dt( int *key) { scanf( "%d", key ); return 1; } int main( void ) { int code,key; code = in_dt( &key); return 0; }

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

  • ベストアンサー
  • liar_adan
  • ベストアンサー率48% (730/1515)
回答No.2

>結局、コード2は正しいのでしょうか? >それともおかしいのでしょうか? 正しいです。 ちゃんと int code,key; のところで、keyのデータを入れるところが宣言されています。 これがもしコード2で、 >int code; >int *key; >code = in_dt( key); とするとエラーが出ます。理由はコード1と同様です。 (#1の最後は舌足らずでしたね。すみません。) 要するにコード1とコード2の違いは、 int *key;となっているかint key;となっているかでして、 int *key;宣言の直後には、データの本体を記憶するべき場所が(まだ)存在していません。 前記のようにしないと使えないということです。 「値が割り当てられてない」というのはそう言うことを行っています。

VitaminBB
質問者

お礼

回答ありがとう御座います。 大変良く判りました。 これまでの理解は、80%にとどまっており、今回残りの20%が判ったという感じです。 ところで、省略してしまったのでコードの中にはありませんが、code = in_dt( &key);のあとで 変数keyを用いた処理を行います。 この時、コード2は期待通り動きますが、コード1は動きません。 (引数でkeyを渡しているかいないかの差) 自分でも大体判っているつもりですが、何となく漠然としており、少し詳しく教えていただけたらうれしいのですが。

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

その他の回答 (4)

  • ret
  • ベストアンサー率40% (8/20)
回答No.5

お書きになられたことであっていると思いますよ。 関数内で何かしらの処理を行い (今の場合はscanfですね) それをmainで使えるようにするために引数としてポインタで渡しているのでしょう。 プログラムの書き方は人によって様々で、 何がいいかなんて余り言えませんが、 大体の場合、 int in_dt( void ) { int key; scanf( "%d", &key ); return key; } int main( void ) { int key, code = 1; key = in_dt(); //keyを使った処理 return 0; } と書くかな?と思うのですが…(^^;。 だってcodeって関数の戻り値は常に1でしょ?。 最後に >mainで値が決まっていないkeyをin_dtに渡していることが不自然に感じられました。 繰り返しになりますが、引数で渡しているのはintで宣言した変数のポインタです。 int宣言時にポインタとしてはメモリアドレスを既に持つことになります。 ですから、keeは確かに値が決まっていませんが、 *keyの値は既に決まっています。 説明…余りうまくないかもしれませんが、 VitaminBBさんの書かれた内容であっているということです

VitaminBB
質問者

お礼

回答ありがとう御座います。 これですっきりしました。 正しいことをどうして正しいのですか?といった類の質問でしたのでちょっと質問に困りました。 いろいろ質問している最中に段々判ってきました。 >だってcodeって関数の戻り値は常に1でしょ?。 文法的に正しいコードとして例に挙げました。 プログラム的には意味が有りませんが。。。(^^;。

全文を見る
すると、全ての回答が全文表示されます。
  • ret
  • ベストアンサー率40% (8/20)
回答No.4

?#2の回答に書かれたご質問の意味がよくわからない…(^^;。 コード1で処理できないとは、 main関数の中で処理できないということでしょうか? それはそうですよね。 コード1でのkeyは int in_dt()のローカル変数なので…。 それより、コード1を実行してscanf関数の実行時によく 例外処理が発生しませんでしたね?(^^;。 (逆に発生しないほうが怖い…) 先ほども回答しましたように コード1のポインタ変数の値は不定です。 つまり何処のアドレスを指しているか解らない。 ですから、keyは???な状態ですから、これを処理することは出来ません。 若しかしたらうまく実行されるかもしれませんが、 それは本当に偶々のことです。 引越し屋さんを呼んで引越し作業をさせているが、 何処に引っ越すのか住所を言っていないようなものです。 荷物は何処に行くのか解りませんよね?(^^;。 蛇足ですが、 値渡しと参照渡しというのはご存知ですよね?。 よく使われる例文に void swap( int a, int b ){ int c; c = a; a = b; b = c; } int mai( void ){ int a = 1, b = 2; swap(a, b); printf("a = %d, b = %d\n", a, b); return 0; } というのがあって、swap関数のなかでa,bの値を変えようというものです。 が…swapの中ではa,bの値は変わりますが、mainの中では変わってはいません。 main君が上司、swap君が部下としましょう。 main君はswap君をいまいち信用していません(^^;。 変数a, bの入れ替えを命じますが、いちいちコピーを取ってそのコピーをswap君に渡します。 上司が部下に書類を渡すのに全て書類のコピーをとり、 そのコピーを部下に渡すものです。 部下はその書類に一生懸命書き込んで上司に報告しても 所詮コピーなので、上司の書類を書き換えたりすることなんて出来ません。 引数を渡されてもmainの変数を書き換えることなんて出来ないのです。 が、上司からコピーじゃなくて書類のある「場所」を教えてもらったらどうでしょう?。 部下は場所がわかるので、自分で書類を取ってきてその書類を書き換えることが出来ます。 これがポインタで渡すということです。 つまり void swap( int* a, int* b ){ int c; c = *a; *a = *b; *b = c; } int main( void ){ int a = 1, b = 2; swap(&a, &b); printf("a = %d, b = %d\n", a, b); return 0; } とすればmainでも値が変わっているぞ…と…。 てか、質問からかなり外れた答えだったでしょうか?。

VitaminBB
質問者

お礼

質問者の私のほうが質問の手を抜いて、回答者の方に気を使わせてしまい申し訳ありません。 回答頂いた内容は基本的には理解できています。 漠然として、何か引っかかることが有ったのですが、何を聞けばよいか ようやく明確になりました。 教えて頂いたコード3のようにmainの中で、a = 1として値が代入された後に、swapに渡している構文は私にとって自然なのですが、 コード2はmainで値が決まっていないkeyをin_dtに渡していることが不自然に感じられました。 (今はコードを見慣れてきたため、不自然に感じられなくなってきましたが) 結局、mainでkeyを使った処理をするためには、keyをグローバル変数的に使うために(ちょっと表現が変?)、 引数として渡す必要がある。という理解をしています。 私の理解がおかしくないか、あるいは何かアドバイスや考え方の訂正等あればご意見をお願いいたします。 <コード2> int in_dt( int *key) { scanf( "%d", key ); return 1; } int main( void ) { int code,key; code = in_dt( &key); //keyを使った処理 return 0; } <コード3> void swap( int* a, int* b ){ int c; c = *a; *a = *b; *b = c; } int main( void ){ int a = 1, b = 2; swap(&a, &b); printf("a = %d, b = %d\n", a, b); return 0; }

VitaminBB
質問者

補足

改めて端的に書くと、 コード2において 何も代入されていない変数keyをわざわざ引数で渡しているのはどうしてか? ということです。

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

ポインタ変数はアドレスを値としてもつ関数ですよね。 コード1の場合、int型のポインタ変数を宣言していますが、 その値としてアドレスを代入していません。 これが関数内でも int key; scanf("%d", &key); としたなら警告は出ないはずです。 コード2はint型の変数を宣言して、 関数にポインタとして渡していますね。 int型の変数を宣言した時に、 既にこのアドレスは決まっています。 (メモリ上のどこかにint型変数が作られるのですから、 当然ですよね。) コード2でも int* key; を宣言して、関数にポインタとして渡した場合は 警告が出るはずですよ。 要はポインタ変数を宣言しただけでは何処のアドレスを指しているかわからず不定の値となる。int型の変数などを宣言してポインタとして使っても、 その変数のアドレスがわかっているので不定とならない ということです。 コード1のように引数をvoidとしたいなら int in_dt( void ) { int key; scanf( "%d", &key ); return 1; } と書きましょう。 …scanf関数自体…お勧めできませんが…(^^;。

VitaminBB
質問者

お礼

回答ありがとう御座います。 大変良く判りました。 #2のほうに追加質問をしました。 出来ればアドバイスお願いします。 (ちょっと判り辛い質問になってしまいましたが。。。)

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

ポインタは、「住所が書かれたメモ用紙」です。 住所そのものではありません。 最初に*keyと宣言したところでは、住所用のメモ用紙が作られただけです。どんな値が入っているかわかりません。 もしかすると、他の重要なデータのある住所(アドレス)が、 たまたま入っているかもしれません。 そうなったら大変で、データを壊してしまいます。 他人の住んでいる家に、勝手に土足で踏み込むようなものです。 先にデータを入れる場所を宣言し、 int *key; int key_data; key = &key_data; のようにしなければいけません。 関数の引数で*keyとしている場合には、それ以前の状況を調べることができないので、警告が出ません。

VitaminBB
質問者

お礼

>関数の引数で*keyとしている場合には、それ以前の状況を調べることができないので、警告が出ません。 コード2で警告が出ない理由はわかりました。 >先にデータを入れる場所を宣言し、 >int *key; >int key_data; >key = &key_data; >のようにしなければいけません。 結局、コード2は正しいのでしょうか? それともおかしいのでしょうか? お教えください。お願いします。

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

関連するQ&A

  • mallocで引数に変数を入れると警告がでます

    #include<stdio.h> int main(void){ int n,i; int* array; puts("n=?"); scanf("%d",&n); array = (int*)malloc(sizeof(int) * n); for(i=0;i<n;i++) *(array+i) = i; for(i=0;i<n;i++) printf("%d ",*(array+i)); puts(""); return 0; } C言語で、上述のプログラムをコンパイルしたところ、 9: warning: incompatible implicit declaration of built-in function ‘malloc’ と警告がでます。 ./a.outで普通に実行できるのですが、 警告がでるということは、もっと正しいやり方があるということでしょうか?

  • グローバル変数について

    ◎1--------------------------------- #include<stdio.h> void func(void); int glb; int main(void) { int a=20; glb=30; printf("main a=%d glb=%d\n",a,glb); func(); return 0; } void func(void) { int b=88; printf("func b=%d glb=%d\n",b,glb); } ------------------------------------- ◎1の実行結果----------------------- main a=20 glb=30 func b=88 glb=30 ------------------------------------- ◎2--------------------------------- #include<stdio.h> void func(void); int glb; int main(void) { int a=20; func(); printf("main a=%d glb=%d\n",a,glb); return 0; } void func(void) { int b=88; int glb=30; printf("func b=%d glb=%d\n",b,glb); } ------------------------------------- ◎2の実行結果----------------------- func b=88 glb=30 main a=20 glb=0 ------------------------------------- 以上2つのプログラムで、◎1は参考書を参考に作成したものです。 ◎1のプログラムで、グローバル変数glbの値をmain( )関数内で設定していたので、次に◎2のようにfunc( )という関数プロトタイプ内で、グローバル変数glbの値を設定し、main( )関数内のprintf文でも表示させようと思ったら、「glb=0」となってしまいました。 なぜこのようになってしまうか、教えてもらえたら嬉しいです。

  • プログラムがうまく動作しない

    int型変数aとbにそれぞれ値を入力し、それらをかけた結果を出力するプログラムをつくりました。もし文字が入力されたら yarinaoshi と表示し再びaに値を入力するように指示します。しかしこのプログラムはデバグしても何のエラーもないのですが、実際に実行し文字を入力すると Microsoft C++ Debug Library というダイアログボックスが出てきて Abort, Retry, Ignore の三つのボタンがでてきます。どれを選んでも作業は止まってしまい、思ったような結果が得られません。一体どうすればいいのでしょうか?  以下がそのプログラムのソースコードです。 #include <stdio.h> #include <ctype.h> #include <stdlib.h> int kakezan(int a, int b); int main(void) { int dt= 1; int a, b; while(dt !=0){ printf("Int1:"); scanf("%d", &a); if(isalpha(a) != 0) { printf("yarinaoshi"); scanf("%d", &a); } printf("Int2:"); scanf("%d", &b); dt = kakezan(a, b); printf("Result:%d\n", dt); } return 0; } int kakezan(int a, int b) { int dt; return dt = a*b; }

  • 警告 W8065について。

    このプログラムを実行したら、実行結果は思い通りになったのですが、 「警告 W8065…プロトタイプのない関数」 と言うのが出ました。  (1)これを消すにはどうすればよいのかを教えてください。  (2)このプログラムはわざと4つに分けているのでこの状態のままプログラムのどこをいじればよいのかを教えてください。 OSはWindows XPでボーランドのコンパイラを使用しています。 #include<stdio.h> int hiki(); int kake(); int waru(); int main(){ int a,b; printf("一つ目の数字\n"); scanf("%d",&a); printf("二つ目の数字\n"); scanf("%d",&b); printf("計%d\n",a+b); hiki(); return 0; } int hiki (){ int c,d; printf("一つ目の数字\n"); scanf("%d",&c); printf("二つ目の数字\n"); scanf("%d",&d); printf("計%d\n",c-d); kake(); return 0; } int kake (){ int e,f; printf("一つ目の数字\n"); scanf("%d",&e); printf("二つ目の数字\n"); scanf("%d",&f); printf("計%d\n",e*f); waru(); return 0; } int waru (){ int g,h; printf("一つ目の数字\n"); scanf("%d",&g); printf("二つ目の数字\n"); scanf("%d",&h); printf("計%d\n",g/h); return 0; }

  • getchar()について 教えてください。

    visual studio 2010 professinalで以下のソースをデバッグして ”続行するには何かキーを押してください!”  で待機させたいのですが getchar()一個だけでは実現しません。   2個重ねるとOKです。どうしてでしょうか。  -------------- 以下のようにscanf関数がなければokということは突き止めたのですが、、、。  ご教授ください。 #include <stdio.h> int main(void) { int i; printf("なにか数字を入力してください。\n"); scanf("%d",&i); printf("今あなたが入力した数字は%dです。\n",i); printf("続行するには何かキーを押してください!"); getchar(); //getchar(); return 0; } ---------------------------------------------------------------- int main(void) { printf("続行するには何かキーを押してください!"); getchar();   return 0; }

  • 数値の連続入力終了条件について

    C言語初心者です。よろしくお願いします。 早速質問なのですが、while文を使ったscanf()関数による数値連続入力で、 ◎1---------------------------------------------- #include<stdio.h> int main(void) {      double dt,sum=0.0;      while(scanf("%lf",&dt) !=EOF){   sum=sum+dt; }   printf("合計=%f\n",sum); return 0; } ---------------------------------------------- ◎1のようにすれば、Ctrl+ZでEOFが返されたら終了とわかるのですが、今度は「0」が入力されたら処理を終了するというプログラムで、 ◎2---------------------------------------------- #include<stdio.h> int main(void) {      double dt,sum=0.0;      while(scanf("%lf",&dt) !=0.0){   sum=sum+dt; }   printf("合計=%f\n",sum); return 0; } ---------------------------------------------- ◎2のようにすると「0」が入力されても、終了せず、以下に示す◎3のように、しないと終了出来ません。 ◎3---------------------------------------------- #include<stdio.h> int main(void) {      double dt,sum=0.0;          scanf("%lf",&dt);      while(dt!=0.0){   sum=sum+dt; scanf("%lf",&dt); }   printf("合計=%f\n",sum); return 0; } ---------------------------------------------- ◎2で何故、◎1のように出来ず、◎3のようなscanf()を1回目、2回目と判定を入れなければならないか教えて下さい。

  • 変数の値がおかしくなる

    以下のようなプログラム(DLLとEXE)を書いたのですが、変数の値がおかしくなる(●参照)箇所があります。原因がお分かりになりましたら、ご回答をよろしくお願い致します。 ●mkdll.cppの、sub1()の(※1)までは、input[]が正しい値で入っているが、(※2)で値がおかしくなる。(※1)から(※2)までで、input[]は参照するだけです。 ---test.cpp(EXE)--- … main(){ int input[10],output[10]; int err; CDLL DLL; err = DLL.func(input,output); … return(0); } ---test.cpp End--- ---mkdll.h(DLL)--- … class __declspec(dllexport) CDLL{ public: int func(int *input, int *output); private: int sub1(int *input, int *output); int sub2(int in, int out); … }; ---mkdll.h End--- ---mkdll.cpp(DLL)--- #include "mkdll.h" … int CDLL::func(int *input, int*output){ int i; int error; error = sub1(input, output); return(error); } int CDLL::sub1(int *input, int *outout){ int i; int in1, in2, out1, out2; int err; //(※1) for(i=0; i<5; i++){ err = 0; in1 = input[i*2]; in2 = input[i*2+1]; //(※2) err = sub2(in1, out1); if(err != 0) return(err); … } } … ---mkdll.cpp End---

  • printfが後で実行されます。

    最近、プログラミングを始めた初心者です。 エクリプスを使い、次のようなプログラムを作ったのですが、 実行結果が思いと違うのです。 #include<stdio.h> int main(void) { int i, dt; printf("数値を入力:"); scanf("%d", &dt); i = 2; while(dt != 1) { while(dt % i == 0) { dt = dt / i; printf("%d\n", i); } i ++; } return 0; } 実行結果 60 数値を入力:2 2 3 5 数値を入力:の後に、scanfで入力したいのですが、 入力したあとでないと、printfの内容が表示されないのです。 コードは大丈夫だと思うのですが、、、 初心者なので、何をどうすれば解決するのか検討もつきません。 どなたかお分かりになる方、よろしくお願いいたします。

  • Borland C++ Compiler 5.5の警告について

    Borland C++ Compiler 5.5を使用してコンパイルしているのですが、 下記のソースをコンパイルするとエラーがでます。 #include <stdio.h> ------test.c------ int main(void) { int a; int b=0; b = a; return 0; } 警告 W8004 error.c 6: 'b' に代入した値は使われていない(関数 main )という警告なのですが、初期化をしている変数すべての警告がでてしまい困っています。 この警告だけを表示させない方法等あるのでしょうか?

  • Cのローカル変数でstatic以外の使い方?

    C言語の課題について教えてください [課題] 以下の関数がある。各関数の引数、変数は自由に設定していい ・int main() ・void func() ・Point *get() { /* 構造体のアドレスを返す */ } ・構造体 typedef struct { int x; int y; int h; int w; }Point; 問題 main関数から、func関数を経由して、get関数を経由し値を取得し、表示する 以下が考えたソースになりますが、これだと、 ローカル変数でstaticを使っているので、get関数が固定値ではなく、 取得のたびに値が変わるような場合には、だめだといわれました。 考えたのですがよくわからないので、どういう場合に駄目なのかと、 どのように修正すればいいのか教えてください。 #include <stdio.h> typedef struct { int x; int y; int h; int w; }Point; void func(Point **); Point *get(); int main(void){ Point *get; func(&get); printf("get.x:[%d]\n",get->x); printf("get.y:[%d]\n",get->y); printf("get.h:[%d]\n",get->h); printf("get.w:[%d]\n",get->w); return 0; } void func(Point **pw){ *pw = get(); printf("Wrapper: pw==%p\n",pw); } Point *get(void) { static Point pget; pget.x = 2; pget.y = 2; pget.h = 30; pget.w = 40; return &pget; }