どうしていいのか解りません

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

どうしていいのか解りません

#1

投稿記事 by Sora » 17年前

scanf関数を使用して、文字列を10回入力し、最も大きな文字列を表示
+文字列の比較はstrcmpを使用
+未入力の場合はエラーとし、もう一度入力
scanf関数を使用して、数字を10回入力し、最も大きな奇数を表示
+未入力、半角数値以外の入力はエラーとし、もう一度入力

なのですが、エラー処理が出来ません。後々関数化しなければならないのですが
関数化もよく解りません;

自分で作った範囲は
#include<stdio.h>
#include<string.h>
#include<ctype.h>

int main(){
	int cnt=0, max1=0 , cnt2, su=0,moji=0;
	char str[50],max[50];

	for(;cnt<10;cnt++){
		printf("%d回目の入力をしなさい" , cnt+1);
		while(1){
			str[moji] = getchar();
			if(str[moji] == '\n'){
				
				break;
				}
			moji++;
		}
			if(str[0] == '\n')
				printf("数値を入力してください。\n");
			else
				break;
			
		}
		
		if(strcmp(str , max) == 1){
			strcpy(max , str);
		}
	}
	printf("一番大きいのは%s\n" , max);
	
	
	
	
	printf("数字を10回入力してください。\n");
	
	for(cnt2=0;cnt2<10;cnt2++){
			printf("%d回目の入力をしてください。" , cnt2+1);
			scanf("%d" , &su);

		if((su%2) != 0){
			if(su>max1){
				max1 = su;
			}
		}
	}
	printf("一番大きい奇数は>%d" , max1); 
}
ご助力お願いいたします。

御津凪

Re:どうしていいのか解りません

#2

投稿記事 by 御津凪 » 17年前

字下げがおかしいところがあるのは混乱の元になりますので正したほうが良いでしょう。

関数化をせずに考えると、for 文ではなく、while 文を使うと、
エラーが発生した所で continue を使えば、
再度(同じ回の)入力待ちすることが出来ます。

具体的にはこんな感じになると思います。
(文字列入力&処理のみ抜粋)
while(cnt<10){
	moji = 0; // 初期化
	printf("%d回目の入力をしなさい" , cnt+1);
	while(1){
		str[moji] = getchar();
		if(str[moji] == '\n'){
			str[moji] = '\0'; // 安全に処理するために NULL 文字に置き換え
			break;
		}
		moji++;
	}
	if(str[0] == '\0'){ // moji == 0 でもOK
		printf("数値を入力してください。\n");
		continue; // 再度入力へ
	}
	if(strcmp(str , max) > 0){ // 大小をチェックする場合は 0 より大きいか小さいかを確認したほうが良い
		strcpy(max , str);
	}
	cnt++; // 次の入力回へ
}
printf("一番大きいのは%s\n" , max);
色々と変わっていますが、変更の要点は、

・moji が初期化されていないので、str の配列を超える可能性がある
・'\n'を'\0'に置き換えているのは安全のためと、正しく比較するため
・エラーが発生した回をもう一度やり直すため、正常処理した時のみ cnt を +1

となっています。

Sora

Re:どうしていいのか解りません

#3

投稿記事 by Sora » 17年前

#include<stdio.h>    /*stdio.hをインクルードする*/
#include<string.h>   /*string.hをインクルードする*/
#include<ctype.h>    /*ctype.hをインクルードする*/ 

int main(){                                /*メインクラス*/
	int cnt=0, max1=0 , cnt2, su=0, moji=0;       /*int型宣言*/
	char str[50],max[50];                  /*char型で宣言*/

	while(cnt<10){
		moji == 0;                    
		printf("%d回目の入力をしなさい" , cnt+1);
		while(1){
			scanf("%s" , str[moji]);
			if(str[moji] == '\n'){
				str[moji]='\0';
				break;
			}
			moji++;
		}
		if(str[0] == '\0'){
			printf("もう一度入力しなおしてください");
			continue;
		}
		if(strcmp(str , max) > 0){
			strcpy(max , str);
		}
		cnt++;
	}
	printf("一番大きいのは%s\n" , max);
	
	
	
	printf("数字を10回入力してください。\n");
	
	for(cnt2=0;cnt2<10;cnt2++){
			printf("%d回目の入力をしてください。" , cnt2+1);
			scanf("%d" , &su);

		if((su%2) != 0){
			if(su>max1){
				max1 = su;
			}
		}
	}
	printf("一番大きい奇数は>%d" , max1); 
	rewind(stdin);
	getchar();
}
書き直してみたのですが、1回目の処理から抜け出さず
無限ループを繰り返します。
getcharは1文字づつ取り出す処理ですが
scanfとどうちがうのでしょうか?
また半角英数字以外のエラーは。。。
islower(c)
こういう関数を見つけたのですが、int型でないと使えないらしく
この場合どう適応させていいのかよくわかりません;

質問ばかりで申し訳ないのですが、よろしくお願いいたします。

御津凪

Re:どうしていいのか解りません

#4

投稿記事 by 御津凪 » 17年前

> getcharは1文字づつ取り出す処理ですが
> scanfとどうちがうのでしょうか?

getchar() は、入力された文字列から一文字読み込んで返します。
一方、scanf() は、printf() のように指定された書式設定に従って文字列を読み込みます。
単に文字列として読むのであれば scanf() が楽です。
しかし、 printf() とは違い、データを入れる変数はポインタを渡さなければなりません。
上記のコードでは、
scanf("%s" , str);
となり("[moji]"は不要)、str には一行分(正確には改行・空白文字の前まで)入るので、
ループ処理も不要です。
したがって、
while(cnt<10){
	//moji = 0; // "=="は間違いなので修正、というより不要
	printf("%d回目の入力をしなさい" , cnt+1);
	scanf("%s" , str);
	if(str[0] == '\0'){
		printf("もう一度入力しなおしてください");
		continue;
	}
	if(strcmp(str , max) > 0){
		strcpy(max , str);
	}
	cnt++;
}
となります。

scanf で一つ注意するのは、空白を含む文字列を読み込むと、最初の空白までしか読み込めません。
きっちり入力を読み込みたい場合は gets() に置き換えると良いでしょう。

> また半角英数字以外のエラーは。。。
> islower(c)
> こういう関数を見つけたのですが、int型でないと使えないらしく
> この場合どう適応させていいのかよくわかりません;

islower() は英小文字を判別する関数なので、 isalnum() を使います。
使い方は、1文字ずつ渡してチェックします。
int i;
for(i = 0;i < strlen(str),++i){ // 全ての文字についてチェック
	if(!isalnum(str)){
		// 半角英数字でない場合にエラー
	}
}

チェックしているのは半角英数字なので、記号や空白文字もエラーとして判別されます。
記号の判別は isgraph()、空白の判別は isspace() となっています。

Mist

Re:どうしていいのか解りません

#5

投稿記事 by Mist » 17年前

グーグル先生をうまく使いこなしましょう。
http://programnet.hp.infoseek.co.jp/cla ... nsole.html

例えば3文字入力してEnterを押すと3文字が読み込まれて4文字目に\0がセットされます。

> scanf("%s" , str[moji]);
これは大間違いです。
入力された文字列はとんでもないところに入っているのでbreakするための条件を満たしません。

正しくは
scanf("%s", str);

文字列を一回のscanfで取得できるのでwhileによる繰り返しもいりません。

> int型でないと使えないらしく
そんなことはないです。
値を渡すのであればcharやshortでも問題ありません。(ポインタを渡すのはだめ)

半角英数字をチェックしたいのだったらislowerは違うと思う。
isalphaとisdigitかな。

Sora

Re:どうしていいのか解りません

#6

投稿記事 by Sora » 17年前

ありがとうございます。
なんとなくうやむやにしていた部分が結構はっきりして
理解できたのかなと思います。
str[0]=='\0'は、普段終端値の'\0'が未入力の場合は一番初めに来るってことを
利用しているんですよね。
一応書き換えて、↓を動かしてみたんですが
うまく処理に入りません。入力画面で
1回目の入力をしなさい の時点でエンターキーを押すと
そのまま下へ下がっていくばかりで文字か入力されるまで
次の処理に行きません。'\n'に書き換えてみてもだめでした。
なぜなんでしょうか;

一応google先生は検索しているんですが、うまくできず。。。
まだ初めて1ヶ月もたたないんですが、早くも挫折しぎみです;;
while(cnt<10){
		printf("%d回目の入力をしなさい" , cnt+1);
		scanf("%s" , str);
		if(str[0] == '\0'){
			printf("もう一度入力しなおして下さい。");
			continue;
		}
		if(strcmp(str , max) > 0){
			strcpy(max , str);
		}
			cnt++;
	}
	printf("一番大きいのは%s\n" , max);
で書き直しましたが、

Mist

Re:どうしていいのか解りません

#7

投稿記事 by Mist » 17年前

> そのまま下へ下がっていくばかりで文字か入力されるまで

scanfは、スペース、Enter以外の入力が無いとscanf関数が終了しません。
(もしかしたら方法があるのかもしれないけど私は知りません)

scanf("%s" , str);
printf("scanf抜けた\n");

というようにしてみてください。
scanfが終わっていないことがわかります。
こういうかんじでprintfを利用してソースのどの部分が走っているかを確認する方法を
printfデバッグといいます。

Sora

Re:どうしていいのか解りません

#8

投稿記事 by Sora » 17年前

> scanfは、スペース、Enter以外の入力が無いとscanf関数が終了しません。
ということはscanfで未入力エラーの対処は不可能と言うことでしょうか?;

> scanf("%s" , str);
> printf("scanf抜けた\n");
このようにやってみましたが、やはり未入力の時は「抜けた」と出ず
終了せず、入力を待ちます。

2つ目の方なのですが、半角数値以外エラーなのでisdigitを使って作ってみたんですが・・・
いまいち?無限ループを繰り返します。まだ練ってる最中なのですが
経過までに。
#include<stdio.h>    /*stdio.hをインクルードする*/
#include<string.h>   /*string.hをインクルードする*/
#include<ctype.h>    /*ctype.hをインクルードする*/ 

int main(){                                /*メインクラス*/
	int cnt=0, max1=0 , cnt2=0,i=0,swich=0;        /*int型宣言*/
	char str[128],max[128],su[128];                  /*char型で宣言*/

	while(cnt<10){
		printf("%d回目の入力をしなさい" , cnt+1);
		scanf("%s" , str);
		printf("scanf抜けた\n"); 
		if(str[0] == '\0'){
			printf("もう一度入力しなおして下さい。");
			continue;
		}
		if(strcmp(str , max) > 0){
			strcpy(max , str);
		}
			cnt++;
	}
	printf("一番大きいのは%s\n" , max);
	
	
	
	printf("数字を10回入力してください。\n");
	
	while(cnt2<10){
		printf("%d回目の入力をしてください。" , cnt2+1);
		scanf("%d" , su);
		swich = 0;
			for(i=0;i<strlen(su);++i){
				if(isdigit(su)==0){
					printf("もう一度入力しなおしてください");
					swich = 1;
					break;
				}
			}
			if(swich == 1){
				continue;
			}
			for(i=0;i<strlen(su);++i){
				if((su%2) != 0){
					if(su>max1){
						max1 = su;
					}
				}
			}
			cnt2++;
	}
	printf("一番大きい奇数は>%d" , max1);
}

初心者・・・なので大目にみていただければ・・・。

御津凪

Re:どうしていいのか解りません

#9

投稿記事 by 御津凪 » 17年前

scanf() に指定されている"%d"は、入力した文字列を数値に<u>変換して</u>変数に格納します。
変数 su は文字列なのでこれは間違いです。(正しい値が入りません)

int型の変数のポインタを渡し、後は数値として比較、処理すれば問題ないでしょう。

Mist

Re:どうしていいのか解りません

#10

投稿記事 by Mist » 17年前

> ということはscanfで未入力エラーの対処は不可能と言うことでしょうか?;
scanfを使って一文字ずつ取得すれば出来るかと。
getchar使うのとなんら変わらなくなってしまいますが(^^;

御津凪さんのを改造(入力部分のみ)
moji = 0; // 初期化
printf("%d回目の入力をしなさい" , cnt+1);
while(1){
    scanf("%c", &str[moji]);
    if(str[moji] == '\n'){
        str[moji] = '\0'; // 安全に処理するために NULL 文字に置き換え
        break;
    }
    moji++;
    // ここに入力文字数が127文字以下になるチェック入れたほうがいいよ
}
> このようにやってみましたが、やはり未入力の時は「抜けた」と出ず
> 終了せず、入力を待ちます。
いや、だからscanfが終了してないってことがわかるでしょ、って意味なんですが(^^;

http://wisdom.sakura.ne.jp/programming/c/c58.html
ここ読んでscanfの使い方について勉強してください。
中途半端な知識で課題を解決しようとしても余計に時間を食うだけだと思います。

Sora

Re:どうしていいのか解りません

#11

投稿記事 by Sora » 16年前

あれから自分なりに工夫して考えてみたんですが、
2つ目の(未入力エラーと数値以外を省くエラー)プログラムがうまくいきません。
未入力も数値も何でもかんでも省いてしまう状態です。
getcharのようにscanf関数を使うと正しく奇数が出力されなくなり
エラー処理をくっつけると省いてしまう・・という感じです。
眺めてみたり、printfデバック、もやってみたのですが。。。。
未熟者ですがご指南いただければと思います。
#include<stdio.h>    /*stdio.hをインクルードする*/
#include<string.h>   /*string.hをインクルードする*/
#include<ctype.h>    /*ctype.hをインクルードする*/ 

int main(){                                          /*メインクラス*/
	int cnt=0,max1=0,cnt2=0,i=0,swich=0,soe=0;       /*int型宣言*/
	char str[128],max[128],su[128];                  /*char型で宣言*/

	while(cnt<10){
		soe=0;
		printf("%d回目の入力をしなさい" , cnt+1);
		while(1){
			scanf("%c" , &str[soe]);
			if(str[soe] == '\n'){
				str[soe] = '\0';
				break;
			}
			soe++;
		}

		if(soe>=127){
			printf("入力文字数をオーバーしています。\nもう一度入力してください。\n\n");
			continue;
		}
		if(str[0] == '\0'){
			printf("もう一度入力して下さい。\n\n");
			continue;
		}
		if(strcmp(str , max) > 0){
			strcpy(max , str);
		}
			cnt++;
	}
	printf("一番大きいのは%s\n" , max);
	
	
	printf("数字を10回入力してください。\n");
	
	while(cnt2<10){
		i=0;
		printf("%d回目の入力をしてください。" , cnt2+1);
		/*scanf("%c" , su);*/
			while(1){
				swich = 0;
				scanf("%c" , &su);
				if(su == '\n'){
					su = '\0';
					swich = 2;
					break;
				}
				if(isdigit(su)==0){
					swich = 1;
					break;
				}
				i++;
			}
			if(swich == 1){
				printf("数値を入力しなおしてください\n");
				continue;
			}
			if(swich == 2){
				printf("未入力ですもう一度入力してください。\n");
				continue;
			}
			for(i=0;i<strlen(su);++i){
				if((su%2) != 0){
					if(su>max1){
						max1 = su;
					}
				}
			}
			cnt2++;
	}
	printf("一番大きい奇数は>%d" , max1);
	rewind(stdin);          /**/
	getchar();
}

御津凪

Re:どうしていいのか解りません

#12

投稿記事 by 御津凪 » 16年前

while 文を抜ける時、swich が必ず 1 か 2 になるのが問題です。
正しく動作するには、未入力チェックを行っているところで、
if(swich == 2 && i == 0){
	printf("未入力ですもう一度入力してください。\n");
	continue;
}
と赤字部分を追加すると、正しく入力判定が出来るはずです。
これは i の値が 0 なら未入力だと判定しています。
(i が 1 以上なら何か入力されているため)

Sora

Re:どうしていいのか解りません

#13

投稿記事 by Sora » 16年前

早速直してみたところ数値のみ読み取りました!
が・・・

あと問題点が2つありまして(2つ目のプログラムで)

・例えば「qqq」と入力すると

 数値を入力しなおしてください
 1回目の入力をしてください。数値を入力しなおしてください。
 1回目の入力をしてください。数値を入力しなおしてください

 1回目の入力をしてください。未入力ですもう一度入力してください
 1回目の入力をしてください>

 このような感じで緑色の部分が入力した文字-1の回数出力される事
 緑~赤字の部分が不要なこと。 

・数値を入力していっても
 (例)
    5・9・999・999・100・1・1・555・999・5
 と入力した場合、結果は999になるはずが57と入力すらしていない数値になることです。
 
これはscanf関数をgetcharの用に使い出してからのエラーでいまいち?です。
もう少し調べて練ってみます。

御津凪

Re:どうしていいのか解りません

#14

投稿記事 by 御津凪 » 16年前

一つ目の問題は、scanf で全ての文字を読み取っていないのが原因です。
getchar 関数に差し替えても同様の問題が発生します。

対処するには、いったん全て('\n'まで)の文字を読み取った後、
読み取った文字列が数値かどうかチェックします。

二つ目の問題で出ている「57」とは、'9'という文字のコード値です。
つまり、文字列で読み込んでいるので、数値に変換する必要があります。

変換方法はいくつかありますが、手っ取り早い方法で、 atol 関数で変換できます。

上の方でも書きましたが、scanf に"%d"を指定することでも数値を格納できます。
が、入力によっては最後まで読み込まない可能性がありますので、
いくつか書き加える部分が出てきます。

閉鎖

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