ページ 1 / 1
テストの合計点の問題で最初に0を代入する意味について教えてください(他1つ)
Posted: 2013年3月27日(水) 02:55
by がむ
一昨日C言語を始めたばかりの超初心者なのですが、二つ質問があります
やさしいCという参考書に「3科目の点数を入力して合計点と平均点を求めよ。」という問題がありました
コード:
#include <stdio.h>
int main(void)
{
int sum=0;
int num=0;
printf("科目1の点数を入力してください\n");
scanf("%d",&num);
sum += num;
printf("科目2の点数を入力してください\n");
scanf("%d",&num);
sum += num;
printf("科目3の点数を入力してください\n");
scanf("%d",&num);
sum += num;
printf("3科目の合計点は%d点です\n",sum);
printf("3科目の平均点は%f点です\n",(double)sum/3);
return 0;
}
が答えなのですが、最初にsumとnumに0を入れる意味がわかりません。
0を入れないで実行したらエラーが起きたのですが、なぜエラーが起きたのかわかりません。
あともう一つ質問なのですが、scanfの構文を使用してリビルドすると毎回
c:\users\ryo\documents\visual studio 2010\projects\sample1\sample1\sample2.c(17): warning C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1> c:\program files\microsoft visual studio 10.0\vc\include\stdio.h(304) : 'scanf' の宣言を確認してください。
と出ます。これってエラーですか?最初エラーかと思ったのですが、デバッグなしで開始を押すと普通に通ります。printf構文だけだとこの文章はでません
開発環境はvisual C++ 2010 です
Re: テストの合計点の問題で最初に0を代入する意味について教えてください(他1つ)
Posted: 2013年3月27日(水) 05:34
by box
がむ さんが書きました:
が答えなのですが、最初にsumとnumに0を入れる意味がわかりません。
0を入れないで実行したらエラーが起きたのですが、なぜエラーが起きたのかわかりません。
得点そのものは0で初期化する必要はありません。
してもいいですが、どうせscanfで値を放り込むので、意味がありません。
一方、合計点は0で初期化しておかないと、変な値になってしまうおそれがあります。
ところで、0で初期化しないで実行したら、どんなエラーが出たのですか?
単に「エラーが起きた」だけでは、状況が伝わりません。
Re: テストの合計点の問題で最初に0を代入する意味について教えてください(他1つ)
Posted: 2013年3月27日(水) 05:55
by box
少しだけ補足します。
今回のnumやsumのように、関数の内部で、staticでないローカル変数を定義した場合、
その中身には何が入っているかわかりません。中身はゴミです。0であるという保証はありません。
点数であるnumは、その後のscanfで値を代入しますから初期値はゴミであっても
いっこうにかまいません。
ところが、合計値であるsumについては、0で初期化しないでいると、
ゴミに点数を足し込んでいきますので、結果がどんな値になるかは全く予想がつきません。
Re: テストの合計点の問題で最初に0を代入する意味について教えてください(他1つ)
Posted: 2013年3月27日(水) 07:06
by box
がむ さんが書きました:
c:\users\ryo\documents\visual studio 2010\projects\sample1\sample1\sample2.c(17): warning C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
warningと書いてありますので、警告です。エラーではありません。
scanfは安全ではないかもしれないので、かわりに、
(Microsoftが独自に持っている関数である)scanf_sを使う方がいいかも、と言っています。
この警告を消したい場合は、コンパイル時のオプションで
_CRT_SECURE_NO_WARNINGS
を指定してください、とも書いてあります。
詳細はオンラインヘルプを確認してください、とも書いてあります。
Re: テストの合計点の問題で最初に0を代入する意味について教えてください(他1つ)
Posted: 2013年3月27日(水) 10:30
by きゃりーわんわん
がむさんが書いたやり方だとsumを初期化する必要がありますね。
上記コードは以下と同じ意味です。
合計点を格納する変数に得点を足しているわけです。
実際に例を出すと分かりやすいと思います。
科目1を60点、科目2を70点、科目3を80点とします。
加算部分をコードにすると以下のようになります。
コード:
// 科目1
sum = sum + 60;
// 右辺のsumには科目1のみが代入されている.
// 科目1+科目2
sum = sum + 70;
// 右辺のsumには科目1+科目2が代入されている.
// 科目1+科目2+科目3
sum = sum + 80;
2行目(科目1をsumに足している行)のコードからわかるとおり、
sumの初期値が0であることを前提とした書き方になっており、
sumの初期値が0ではないと(例えば50とか)、結果が変になることがわかると思います。
そのため、0で初期化してます。
# 変数は極力、初期化するという癖をつけた方が良いです。
Re: テストの合計点の問題で最初に0を代入する意味について教えてください(他1つ)
Posted: 2013年3月27日(水) 16:17
by box
意味のあるコードだけ書く、という私のポリシーに照らすと、
今回の場合は
sumは、numの値を足し込む前に、どこかで必ず0で初期化する
numは初期化しない(どうせscanfで上書きするので)
ということになります。
他の方のポリシーは、存じません。
Re: テストの合計点の問題で最初に0を代入する意味について教えてください(他1つ)
Posted: 2013年3月27日(水) 16:44
by ISLe
「初期化する」と「初期値を代入する」が一部混同されているような感じを受けますが。
規定値が0となる場合でも、明示的に初期化したほうが良い。→可読性の向上
一連の処理の初めに、初期値を代入するようにしたほうが良い。→保守性の向上
どちらにも意味がありますがわたしは後者を優先します。
Re: テストの合計点の問題で最初に0を代入する意味について教えてください(他1つ)
Posted: 2013年3月27日(水) 17:18
by ISLe
一昨日はじめたばかりの方にはかなり難しい問題だと思いますが、興味があれば各パターンにどんなメリット・デメリットがあるか考えてみてください。
コード:
int sum; /* 外部変数は既定で0に初期化されるが */
/* int sum = 0; 明示的に初期化したほうが分かりやすい */
void pattern1(void) /* パターン1 */
{
int num;
/*
* 外部変数を使うと明示的に初期化しなくても良いが…
*/
/* 1番目入力 */
sum += num;
/* 2番目入力 */
sum += num;
/* 3番目入力 */
sum += num;
/* 合計表示 */
}
void pattern2(void) /* パターン2 */
{
int num;
static int sum; /* 静的局所変数は既定で0に初期化されるが */
/* static int sum = 0; 明示的に初期化したほうが分かりやすい */
/*
* 静的局所変数を使うと明示的に初期化しなくても良いが…
*/
/* 1番目入力 */
sum += num;
/* 2番目入力 */
sum += num;
/* 3番目入力 */
sum += num;
/* 合計表示 */
}
void pattern3(void) /* パターン3 */
{
int num;
int sum; /* 自動変数は初期値が不定(どんな値になるか分からない) */
sum = 0; /* 初期値を代入 */
/* 1番目入力 */
sum += num;
/* 2番目入力 */
sum += num;
/* 3番目入力 */
sum += num;
/* 合計表示 */
}
void pattern4(void) /* パターン4 */
{
int num;
int sum; /* 自動変数は初期値が不定(どんな値になるか分からない) */
/* 1番目入力 */
sum = num; /* 最初は代入 */
/* 2番目入力 */
sum += num;
/* 3番目入力 */
sum += num;
/* 合計表示 */
}
Re: テストの合計点の問題で最初に0を代入する意味について教えてください(他1つ)
Posted: 2013年3月27日(水) 17:37
by きゃりーわんわん
ISLe さんが書きました:
「初期化する」と「初期値を代入する」が一部混同されているような感じを受けますが。
確かに上記2つの言葉を意識的に使い分けできていませんでした。
ISLeさん、ご指摘ありがとうございます。
がむさん、自分の説明文は混乱させてしまうかもなのであまり見ない方がよいです。
# だからといって削除はしませんが。
Re: テストの合計点の問題で最初に0を代入する意味について教えてください(他1つ)
Posted: 2013年3月27日(水) 20:23
by がむ
>boxさん
ありがとうござました。理解できました
仰るとおり、numには0を入れなくてもエラーが起きませんでした
box さんが書きました:
ところで、0で初期化しないで実行したら、どんなエラーが出たのですか?
単に「エラーが起きた」だけでは、状況が伝わりません。
warning C4700: 初期化されていないローカル変数 'sum' が使用されます。と警告が出まして、実行すると最初の点数を入力した時点で
Run time check failuer #3 - The variable 'sum' is being used without being initialized とでます
>ISLeさん
もう少し知識をつけたら読み返して参考にさせて頂きます
>きゃりーわんわんさん
とりあえず初期値を代入する癖をつけるようにしてみます
Re: テストの合計点の問題で最初に0を代入する意味について教えてください(他1つ)
Posted: 2013年3月27日(水) 21:17
by だんごさん
他の方が答えていらっしゃいますが、私も…。
まず、intとかで変数を作ると、空きメモリをくれます(たぶん)。しかしその変数には最初、訳の分からない適当な数値が入っています。もしもtestという変数を作って、最初46346が入っていたとします。
テストの点を100点として、testに代入しても46446となりますね。意味不明になります。
しかし、testに0を入れておきます。これが初期化ですね。これに100点を代入してあげると正しく100と入ります。
色々例外はありますが、ややこしくなったり、バグの原因になったりしかねないので最初に初期化するのが最適です。