C言語、while文に関する初歩的な質問

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ted

C言語、while文に関する初歩的な質問

#1

投稿記事 by ted » 14年前

点数を入力、-1を入力し終了するまでの最高点、最低点、平均点、合計点、人数を表示するプログラムなのですが、数字を入力した時点でプログラムが終了してしまいます。正しく動作させるためにはどこが間違っているのでしょうか。長いこと困ってます、よろしくお願いします。

コード:


/* testscore */
 
#include <stdio.h>
#pragma warning(disable : 4996)


int main()

{
	int sum = 0, p = 0, n = 0, max = 0, min = 100;
	
	while(1){
		printf("点数を入力(-1で終了)---");

		scanf("%d", &p);

		if(p == -1)	
			break;	

	
            sum += p;
			n++;

			if(p > max)
				max = p;

			if(p < min)
				min = p;
			
			
            if(n == 0)
				printf("人数が0人の時は終了します\n");
				return -1 ;

			printf("合計点は%d 平均点は%5.1f 最高点は%d 最低点は%d 受験人数は%d人です\n",sum ,(double)sum / n ,max ,min );
	}

	printf("%d人の合計点は%dです\n",n,sum);
	printf("平均点は%5.1fです\n",(double)sum / n);
	printf("最高点は%d、最低点は%dです\n",max ,min);



	return 0;

}


アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: C言語、while文に関する初歩的な質問

#2

投稿記事 by bitter_fox » 14年前

ted さんが書きました:点数を入力、-1を入力し終了するまでの最高点、最低点、平均点、合計点、人数を表示するプログラムなのですが、数字を入力した時点でプログラムが終了してしまいます。正しく動作させるためにはどこが間違っているのでしょうか。長いこと困ってます、よろしくお願いします。

コード:

            if(n == 0)
				printf("人数が0人の時は終了します\n");
				return -1 ;
問題はココです。
if (n == 0)が真の時に実行されるのはprintf("人数が0人の時は終了します\n");だけで、return -1;は常に実行されてしまいます。

コード:

            if(n == 0)
            {
				printf("人数が0人の時は終了します\n");
				return -1 ;
            }
としてください。

こういったぶら下がり構文はバグの温床になるので極力{}で囲むようにしてはどうでしょうか?(僕はすべて{}で囲むようにしています。)
ted さんが書きました:

コード:

        if(p == -1) 
            break;  
 
    
            sum += p;
            n++;
 
あと、インデントによってsum += p;以降の分もif(p == -1)のブロックに見えてしまうので、もっと厳密なインデントを行うことをお勧めします。

[hr][追記]
厳密にインデントすると次のような感じになります。

コード:


/* testscore */

#include <stdio.h>
#pragma warning(disable : 4996)

int main()
{
	int sum = 0, p = 0, n = 0, max = 0, min = 100;

	while(1){
		printf("点数を入力(-1で終了)---");

		scanf("%d", &p);

		if(p == -1)
			break;

		sum += p;
		n++;

		if(p > max)
			max = p;

		if(p < min)
			min = p;

		if(n == 0)
			printf("人数が0人の時は終了します\n");
		return -1;

		printf("合計点は%d 平均点は%5.1f 最高点は%d 最低点は%d 受験人数は%d人です\n",sum ,(double)sum / n ,max ,min );
	}

	printf("%d人の合計点は%dです\n",n,sum);
	printf("平均点は%5.1fです\n",(double)sum / n);
	printf("最高点は%d、最低点は%dです\n",max ,min);

	return 0;
}
これだとreturn -1;がif (n == 0)のブロックに入っていないというのが明らかですね。

ted

Re: C言語、while文に関する初歩的な質問

#3

投稿記事 by ted » 14年前

whileに-1が返っていたのですか、bitter_foxさん、どうもありがとうございました!
僕も{}を必ずつけるようにします。お手数掛けました。

ted

Re: C言語、while文に関する初歩的な質問

#4

投稿記事 by ted » 14年前

解決マークつけておきます。失礼しました。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: C言語、while文に関する初歩的な質問

#5

投稿記事 by bitter_fox » 14年前

ted さんが書きました:whileに-1が返っていたのですか、bitter_foxさん、どうもありがとうございました!
僕も{}を必ずつけるようにします。お手数掛けました。
whileに-1が返っているのではなく戻り値を-1としてmain関数を抜けるという意味になってます。
その証拠に、whileの外に書かれている

コード:

    printf("%d人の合計点は%dです\n",n,sum);
    printf("平均点は%5.1fです\n",(double)sum / n);
    printf("最高点は%d、最低点は%dです\n",max ,min);
が実行されていないはずです。(もしwhileだけを抜けた場合はこの三文+return 0;が実行されているはずです。)

ted

Re: C言語、while文に関する初歩的な質問

#6

投稿記事 by ted » 14年前

bitter_foxさん度々ありがとうございます。

最初の入力で-1を入力した場合に「人数が0人の時は終了します」を正しく表示するために

コード:

        printf("合計点は%d 平均点は%5.1f 最高点は%d 最低点は%d 受験人数は%d人です\n",sum ,(double)sum / n ,max ,min ,n);
    }
	    if(n == 0){
            printf("人数が0人の時は終了します\n");
	    return -1;}
とwhile文ブロックの後にif(n == 0)のソースを持ってくると正しく、

コード:

    printf("%d人の合計点は%dです\n",n,sum);
    printf("平均点は%5.1fです\n",(double)sum / n);
    printf("最高点は%d、最低点は%dです\n",max ,min);
この3文が表示されずに終わりました。
しかしreturnについての認識が甘いようで、今ひとつ理解できません。

コード:

 if(n == 0){
            printf("人数が0人の時は終了します\n");
	    return -1;}
この部分のreturnに何の数字を入れなくても「人数が0人の時は終了します」が表示され正しく終了してしまいます。
サンプルプログラムにはreturn -1 とされていたのでそれに倣ったのですがここにきてreturnの正確な役割がわからなくなってしまいました。

(問題の回答プログラム)

コード:

/* program53.c */
#define _CRT_SECURE_NO_DEPRECATE 
#include <stdio.h>
int main()
{
	int max = 0, min = 100, x, n = 0, sum = 0;
	while (1) {
		printf("点数---- ");
		scanf("%d", &x);
		if (x == -1)
			break;
		sum += x;
		if (x >= max)
			max = x;
		if (x <= min)
			min = x;
		n++;
		printf("n = %d, max = %d, min = %d, sum = %d\n",
			n, max, min, sum);
	}
	
	if (n == 0) {
		printf("受験者数が0の時は計算できません\n");
		return -1;
	}
	printf("最低点 = %d点、最高点 = %d点、受験者数 = %d人、平均点 = %5.1f点\n",
		min, max, n, (double)sum / n);
	return 0;
}
こちらもif (n == 0)のときのreturn -1を0に変えても8に変えても入力しなくても正しく終了します。
何故なのかわかりません。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: C言語、while文に関する初歩的な質問

#7

投稿記事 by bitter_fox » 14年前

ted さんが書きました: しかしreturnについての認識が甘いようで、今ひとつ理解できません。

コード:

 if(n == 0){
            printf("人数が0人の時は終了します\n");
	    return -1;}
この部分のreturnに何の数字を入れなくても「人数が0人の時は終了します」が表示され正しく終了してしまいます。
サンプルプログラムにはreturn -1 とされていたのでそれに倣ったのですがここにきてreturnの正確な役割がわからなくなってしまいました。
return文は関数ブロックを抜けて呼び出し元に値を返すために用います。
main関数の場合はOSやその他の呼び出し元に対して値を返すことになります。
例えば、Windowsからexeファイルをクリックして実行した場合はWindowsに対して値が返されます。(厳密には色々なところを通って返っているわけですが・・・)
ですが、Windowsはこの値を無視してますので特に気にする必要はありません。
また、バッチファイルから呼び出した場合はそのバッチファイルに対して値が返されますので、その戻り値を用いて実行結果(正常終了か異常終了か)を判定したりします。
http://www.geekpage.jp/programming/c/return-main.php

一般に正常終了した場合は0を異常終了した場合は0以外の値を返します。

returnのあとに何も書かなかった時の動作がC言語の規格で定まっているのは戻り値がvoidの関数(つまり何も値を返さない関数)の中で使われた場合のみです。(その時の動作は単に関数を抜けるという意味)
もし、それ以外の関数内で使用された場合にどういった値が返されるのかはコンパイラに依存します。
ですので、戻り値がint型のmain関数内でそのようなreturn文を書くのはよろしくありません。

box
記事: 2002
登録日時: 15年前

Re: C言語、while文に関する初歩的な質問

#8

投稿記事 by box » 14年前

戻り値のあるreturn文は、そのreturn文が属している関数の呼び出し元に対し、
戻り値の値によって異なる動作をさせるために用います。

今回の場合、「そのreturn文が属している関数」はmain関数を指します。
では、「そのreturn文が属している関数の呼び出し元」、つまりmain関数の呼び出し元とは何でしょうか。
それは、
Windows/MS-DOS系のOSではバッチファイル、
UNIX系のOSではシェルスクリプト
などのことをいいます。

元々のサンプルコードでは、main関数内で
return 0;
return -1;
という2種類の値を使い分けています。これは、
先ほど書きましたバッチファイルやシェルスクリプトに対し、
return 0→正常終了
return -1→異常終了
であることを知らせるためのものです。

知らせを受けたバッチファイルやシェルスクリプトでは、呼び出したプログラムの終了結果(サンプルコードでは0か-1)によって、
その後の処理を変更するようなロジックが入ることになります。

バッチファイルやシェルスクリプトが存在せず、単独で動かす場合には
return 0;
return -1;
の両者(あるいは、質問者さんが書かれたretun 8;)には見かけ上の違いは生じません。
0や-1(や8)という戻り値を受け取る側が存在しないためです。

なお、int型の戻り値を求めているmain関数で、単に
return;
と書いた場合、呼び出し元には不定値が返ります。
呼び出し元の動作をどう規定すればよいかがわからなくなりますので、あまり推奨できません。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

ted

Re: C言語、while文に関する初歩的な質問

#9

投稿記事 by ted » 14年前

bitter_fox さん、boxさん、どうもありがとうございます!

この場合のreturnはプログラムの正(0)否(0以外)をバッチファイルに伝えてmain関数を抜ける、ということが理解できました。
さらにmain関数はint型の関数なのでreturnに数字を書かないのはバッチファイルがどう動作するかわからなくなるので危険、ということですね。

閉鎖

“C言語何でも質問掲示板” へ戻る