在C语言中实现只输入数字的一种方法

在C语言中实现只输入数字的一种方法

前言

最近在学习苏小红等教授主编的《C语言程序设计》,在6.4(条件控制的循环)一节中,学习者需要不断完善一个猜数游戏。
在完善的过程中书采用了一种方法,使程序在用户输入非数字(准确说整数)时报错。
但我在实际运行时发现书本的方法存在局限性。经过思考我想出了一种不超出书本第六章内容的一种改良方法。
以下以整数为例:(浮点数类似)

《C语言程序设计》的策略

书中使用了如下的代码实现提示错误信息、清除非法字符、重新输入数据的功能:

int ret, guess;
ret = scanf ("%d", &guess);
while (ret != 1)
{
	while (getchar() != '\n');\\清除缓存区中非法字符,我查到可用fflush (stdin);代替。
	printf("Warning: Enter an INTEGER!\n");
	ret = scanf("%d", &guess);
}

它利用了scanf()函数的返回值:
scanf()的返回值为成功输入的数据的个数
(类似的,printf()的返回值是成功输出的个数

因此如果scanf()读取了一个整形数据,ret = 1,跳过循环直接进行猜数判定;否则不读取,ret = 0,非整型数据被存放到缓冲区;提示错误信息、清除非法字符、重新输入数据。如下图所示。
在这里插入图片描述

看起来针不戳!

氮四!

然而当我们输入一个【数字+字母】的字符串时,却会出现以下结果:
在这里插入图片描述

由于scanf()的读取机制,输入444x时,先读取了444给guess,进行猜数判定。而剩下的x则放到了缓冲区。当scanf()再次读取时,跳过用户直接从缓冲区读取了x,使得ret = 0,进入循环体中。于是输出了两行结果。
我们可以在ret = scanf("%d), &guess)后加入一行while(getchar() != '\n');清除缓存区。此时输入444x时反馈的结果为

The range is between 1 and 444. Try again!

但这个结果依然不太完美:444x本质上仍然不是数字而是字符串,
x444 不行!
444x 行!
这河里吗.jpg
并且,输出小数444.4也会得到此结果。
能否让它们都反馈出

Warning: Enter an INTEGER!

我的想法

我在网上冲浪后发现,有关的讨论对于一个学了点皮毛的新手过于难懂qwq。只好自食其力:
444444xx的被读取的过程中,差别在于缓冲区的内容:前者是换行(我在开始认为是空);后二者是字符x。这给了我灵感:从判定缓冲区的内容入手。
使用getchar()可以从缓冲区读取字符,并且getchar()的返回值就是读取的内容。可以用getchar()的返回值判定。
使用如下代码验证:

#include <stdio.h>
int main()
{
    int d, ret;
    char ch;
    ret = scanf("%d", &d);
    ch = getchar();
    printf("%d, %d, %d, %c", d, ret, ch, ch);
    return 0;
}

分别输入233,233?,sit,prc71得到的结果是

233, 1, 10,
233, 1, -93, (此处问号是全角的,半角输出为233, 1, 63, ?)
0, 0, 115, s
0, 0, 112, p

成功验证了我的想法。
可以发现,以%d输出的getchar()返回值仅在输入数字时为10(此ascii码对应的是换行)
于是可以将书上提供的策略作如下改良:

       scanf("%d", &guess);
       hey = getchar();
       while(hey != 10)
       {
           while(getchar() != '\n');
           printf("Warning: Not an INTEGER!\n");
           scanf("%d", &guess);
           hey = getchar();
       }

如果输入的是一个数字,则getchar()读到了\n,hey = 10,直接进行猜数判定;
否则若输入的内容含有非数字字符,getchar()会读到第一个非数字字符,hey不为10,进入while循环体中,报错并要求重新输入。
最终的成果如下:
在这里插入图片描述

解决了问题。

Update 10.15

忙里偷闲,修改了一些措辞与图片(主要是精确化了数字的表述——整数、浮点数)。同时最近学了函数,添加了函数版本

int GetValidInteger()
{
	printf("Input an integer:\n");
	int n, judge;
	scanf("%d", &n);
	judge = getchar();
	while(judge != 10)
	{
		fflush(stdin);
		printf("Warning: Not an INTEGER!\n");
		scanf("%d", &n);
		judge = getchar();
	}
	return n;
}

//如果不考虑第一次与后续输出的差别,可以简化:
int GetValidInteger()
{
	int n, judge = 0;
	while(judge != 10)
	{
		fflush(stdin);
		printf("Enter an INTEGER!\n");
		scanf("%d", &n);
		judge = getchar();
	}
	return n;
}

当然,int换成float、%d换成%f就可以GetValidFloat()啦。

  • 40
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值