以下のコード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;
}
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;宣言の直後には、データの本体を記憶するべき場所が(まだ)存在していません。
前記のようにしないと使えないということです。
「値が割り当てられてない」というのはそう言うことを行っています。
回答ありがとう御座います。
大変良く判りました。
これまでの理解は、80%にとどまっており、今回残りの20%が判ったという感じです。
ところで、省略してしまったのでコードの中にはありませんが、code = in_dt( &key);のあとで 変数keyを用いた処理を行います。
この時、コード2は期待通り動きますが、コード1は動きません。
(引数でkeyを渡しているかいないかの差)
自分でも大体判っているつもりですが、何となく漠然としており、少し詳しく教えていただけたらうれしいのですが。
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さんの書かれた内容であっているということです
回答ありがとう御座います。
これですっきりしました。
正しいことをどうして正しいのですか?といった類の質問でしたのでちょっと質問に困りました。
いろいろ質問している最中に段々判ってきました。
>だってcodeって関数の戻り値は常に1でしょ?。
文法的に正しいコードとして例に挙げました。
プログラム的には意味が有りませんが。。。(^^;。
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でも値が変わっているぞ…と…。
てか、質問からかなり外れた答えだったでしょうか?。
この回答への補足
改めて端的に書くと、
コード2において
何も代入されていない変数keyをわざわざ引数で渡しているのはどうしてか?
ということです。
質問者の私のほうが質問の手を抜いて、回答者の方に気を使わせてしまい申し訳ありません。
回答頂いた内容は基本的には理解できています。
漠然として、何か引っかかることが有ったのですが、何を聞けばよいか
ようやく明確になりました。
教えて頂いたコード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;
}
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関数自体…お勧めできませんが…(^^;。
回答ありがとう御座います。
大変良く判りました。
#2のほうに追加質問をしました。
出来ればアドバイスお願いします。
(ちょっと判り辛い質問になってしまいましたが。。。)
No.1
- 回答日時:
ポインタは、「住所が書かれたメモ用紙」です。
住所そのものではありません。
最初に*keyと宣言したところでは、住所用のメモ用紙が作られただけです。どんな値が入っているかわかりません。
もしかすると、他の重要なデータのある住所(アドレス)が、
たまたま入っているかもしれません。
そうなったら大変で、データを壊してしまいます。
他人の住んでいる家に、勝手に土足で踏み込むようなものです。
先にデータを入れる場所を宣言し、
int *key;
int key_data;
key = &key_data;
のようにしなければいけません。
関数の引数で*keyとしている場合には、それ以前の状況を調べることができないので、警告が出ません。
>関数の引数で*keyとしている場合には、それ以前の状況を調べることができないので、警告が出ません。
コード2で警告が出ない理由はわかりました。
>先にデータを入れる場所を宣言し、
>int *key;
>int key_data;
>key = &key_data;
>のようにしなければいけません。
結局、コード2は正しいのでしょうか?
それともおかしいのでしょうか?
お教えください。お願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# C pointer? or... 2 2022/03/29 00:47
- MySQL MYSQL エラー 2 2022/10/18 11:37
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# 至急教えてください!プログラミングの問題です。 割られる整数と割る整数を受け取って、商と余りを出力す 3 2022/07/05 10:23
- MySQL 何にかが違うから エラーなんでしょうね! 2 2022/09/18 05:28
- C言語・C++・C# 質問です 下記のコードを分かりやすく解説お願いします 初心者です #include ‹stdio.h 3 2022/05/26 22:03
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
DWORDの実際の型は何でしょうか
-
long型の定数の末尾にLを付ける...
-
C++のfor文について
-
visualstudio C# テキストボッ...
-
typedef enumの使い方を教えて...
-
2重定義って??
-
【#define】 defineで定義した...
-
構造体の要素すべてに対する四...
-
C++ クラスをメンバにもつクラ...
-
main.c:7:43: warning: implici...
-
void func( void )について
-
C言語で分割ファイル先の関数を...
-
C++でboolにintの値を代入する...
-
STLのsortで、プライベート変数...
-
構造体の宣言でエラーが出ます。
-
プログラムの中で別のmainを呼...
-
変数の型を定義しなかった場合...
-
0除算を判定したい
-
unsigned *という宣言について
-
sshdログの意味
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
DWORDの実際の型は何でしょうか
-
long型の定数の末尾にLを付ける...
-
2重定義って??
-
typedef enumの使い方を教えて...
-
visualstudio C# テキストボッ...
-
C++のfor文について
-
関数の実体定義にヘッダファイ...
-
構造体の要素すべてに対する四...
-
ハンドルされていない例外が発...
-
C++でboolにintの値を代入する...
-
変数の型を定義しなかった場合...
-
intとINTの違いは?
-
main.c:7:43: warning: implici...
-
void func( void )について
-
C言語 宣言した変数になにも代...
-
【#define】 defineで定義した...
-
構造体の宣言でエラーが出ます。
-
C言語での方向キー入力判定
-
プログラムの中で別のmainを呼...
-
C言語について質問です。 子プ...
おすすめ情報