🌕

fgetsとsscanfを使って、1ケタの数字を標準入力から受け取る方法

2021/12/20に公開

サンプルコード

1から9までの整数を受け取りたい場合のコードを考えていく。

#include <stdio.h>

int main(void)
{
	int number;
	char str[5];

	str[0] = '\0';
	str[1] = '\0';
	str[2] = '\0';
	str[3] = '\0';
	str[4] = '\0';
	while (1)
	{
		fgets(str, sizeof(str), stdin);
		sscanf(str, "%d", &number);
		printf("str[0]: %c\n", str[0]); //それぞれ何が含まれているかを確認するためにstrの中身を出力
		printf("str[1]: %c\n", str[1]);
		printf("str[2]: %c\n", str[2]);
		printf("str[3]: %c\n", str[3]);	
		printf("str[4]: %c\n", str[4]);
		if (1 <= number  && number <= 9)
		{
			printf("Input number is: %d\n", number);
			return (number);
		}
		printf("Wrong input. Please enter a number. (1 ~ 9)\n");
		
		
	}
}

サンプルコードの問題点

・標準入力がstrの長さを超える場合(今回の例の場合だと2文字以上)、格納されなかった余りの文字は次のループ時に自動的に格納され、Wrong input. Please enter a number.が複数回表示されてしまう。

このサンプルコードでわかること

・ str[4]には常に'\0'が格納される。
・ 入力がstrの長さを超える場合、格納されなかった余りの文字は次のループ時に自動的にstrに格納される。

実行結果

正常:「2」を入力した場合。

$ ./a.out
2 //標準入力
str[0]: 2
str[1]: 
str[2]: 
str[3]: 
str[4]: 
Input number is: 2

正常:「111」を入力した場合

$ ./a.out
111 //標準入力
str[0]: 1
str[1]: 1
str[2]: 1
str[3]: 

str[4]: 
Wrong input. Please enter a number. (1 ~ 9)

問題の挙動:「1111」を入力した場合

$ ./a.out
1111 //標準入力 
str[0]: 1
str[1]: 1
str[2]: 1
str[3]: 1
str[4]:   //文字列の最終尾のため、常に'\0'が入力されている
Wrong input. Please enter a number. (1 ~ 9) 
str[0]:   //`1111`を入力したあとの'\n'(改行、Enter)が、5文字として`str[0]`に格納される。

str[1]:   //`1111`は文字列として認識されるので、`1111\n\0` と最後の'\0'がここに格納。
str[2]: 1 //最初に格納されたものが残っている
str[3]: 1 //最初に格納されたものが残っている
str[4]: 
Wrong input. Please enter a number. (1 ~ 9) //この部分が問題で、2度目の表示がされる。直前に何も入力していないが、最初の標準入力で余った文字分(`\n`と`\0`)への処理。

解決策

・標準入力がstrの長さを超える場合(今回の例の場合だと2文字以上)、格納されなかった余りの文字は次のループ時に自動的に格納されるので、 余計なループを減らすには\nがstrのいずれにもない場合にfgets関数を呼び出し、余分な標準入力を処理する。

#include <stdio.h>

int main(void)
{
	int number;
	char str[5];

	str[0] = '\0';
	str[1] = '\0';
	str[2] = '\0';
	str[3] = '\0';
	str[4] = '\0';
	while (1)
	{
		fgets(str, sizeof(str), stdin);
		sscanf(str, "%d", &number);
		printf("str[0]: %c\n", str[0]);
		printf("str[1]: %c\n", str[1]);
		printf("str[2]: %c\n", str[2]);
		printf("str[3]: %c\n", str[3]);	
		printf("str[4]: %c\n", str[4]);
		if (1 <= number  && number <= 9)
		{
			printf("Input number is: %d\n", number);
			return (number);
		}
		printf("Wrong input. Please enter a number. (1 ~ 9)\n");
		while (str[1] != '\n' && str[2] != '\n' && str[3] != '\n')
			fgets(str, sizeof(str), stdin);
		}
}

実行結果

「1111」を入力した場合。

$ ./a.out
1111 //標準入力
str[0]: 1
str[1]: 1
str[2]: 1
str[3]: 1
str[4]: 
Wrong input. Please enter a number. (1 ~ 9)
            //2度目の「Wrong input. 〜」は表示されず、標準入力が求められる。

Discussion