• ベストアンサー

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

以下のコード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は正しいのでしょうか? それともおかしいのでしょうか? お教えください。お願いします。