一、前言
最近刚好在写一个仿登陆系统,需要多次用到“只能输入整型数据”的scanf,于是我打算使用自定义函数的方式来实现。下面的代码都是在vs中运行的。
二、scanf的特点
特点一:scanf的返回值
scanf()的返回值为成功输入的数据的个数,例如以下代码:
int ret = scanf("%d",&a);
printf("%d",ret);
若输入:111↙
会得到:ret = 1
若输入:aaa
会得到:ret = 0
若输入:^Z↙(注:ctrl+z输入代表输入文件结束符)
会得到:ret = -1
特点二:scanf会"挑食"
对于整型数据,scanf在从缓冲区读入数据时会过滤掉空格符、换行符和水平制表符,也就是说当scanf从缓冲区读入数据时,遇见空格符、换行符和水平制表符就会停止读取
三、尝试
Ⅰ.通过scanf的返回值判断输入数据是否合法:
思路:
int ret, password;
int ch = 0 ;
ret = scanf ("%d", &password);
while ((ch=getchar()) != '\n' && ch != EOF){;}//清空缓冲区
while (ret != 1)
{
printf("密码含有非法字符!请重新输入整型密码!\n");
ret = scanf("%d", &password);
while ((ch=getchar()) != '\n' && ch != EOF){;}//清空缓冲区
}
因为上述代码中scanf只需要读取一个数据,如果scanf()读取了一个整型数据,ret = 1,跳过循环直接进入后续代码。
反之进入循环,清空缓冲区(非法字符)并警告,并重新输入。
缺点:
上述代码当输入"123456x"之类字符串时,scanf会先读取123部分,此时ret的值为1,循环不执行。而字符串中的x则会停留在缓冲区中,被清空缓冲区的代码清除。"123456x"本质上还是一个字符串,当你设置密码为"123456x"但系统却给你保存"123456",这样肯定不行,所以我有了第二个尝试。
Ⅱ.通过读取scanf缓冲区剩余内容判断
前面提到过,scanf遇到空格符、换行符和水平制表符就会停止读取,也就是说这些数据会停留在缓冲区。而我们在输入密码时都需要按回车确认输入,也就是说缓冲区的最后一位一定是换行符'\n',我们只需要以此为基础进行一个简单的判断即可。代码如下:
int ret,password;
int ch =0;
scanf("%d",&password);
ret = getchar();
while(ret != '\n')
{
while((ch = getchar()) != '\n' && ch != EOF){;}//清空缓冲区
printf("密码含有非法字符!请重新输入整型密码!\n");
scanf("%d",&password);
ret = getchar();
}
四、自定义函数以便于多次调用
正如同前面所说,一个程序经常会用到这类仅支持输入整型数据的scanf,所以我尝试将他封装成一个自定义函数,以便于多次调用。这里有如下两种写法:
Ⅰ.无参数,调用返回值
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int input()
{
int ret,password;
int ch =0;
scanf("%d",&password);
ret = getchar();
while(ret != '\n')
{
while((ch = getchar()) != '\n' && ch != EOF){;}//清空缓冲区
printf("密码含有非法字符!请重新输入整型密码!\n");
scanf("%d",&password);
ret = getchar();
}
return password;
}
int main()
{
int a = 0;
a = input();
printf("%d\n",a);
return 0;
}
Ⅱ.利用参数传址
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int input(int *password)
{
int ret;
int ch =0;
scanf("%d",password);
ret = getchar();
while(ret != '\n')
{
while((ch = getchar()) != '\n' && ch != EOF){;}//清空缓冲区
printf("密码含有非法字符!请重新输入整型密码!\n");
scanf("%d",password);
ret = getchar();
}
}
int main()
{
int a = 0;
input(&a);
printf("%d\n",a);
return 0;
}
可能有人会疑惑为什么此处input的参数需要是指针。
我们需要知道,自定义函数和主函数的交互,相当于把主函数中的实参放到函数形参的部分,类似于将一箱凤梨(A)在X地一个个拿出来,克隆一份放到Y地的另一个箱子(B)中,因为有两箱凤梨,X地需要用到凤梨不需要从Y地拿回去,所以此时用户使用自定义函数操作相当于把凤梨B榨汁,而不会影响凤梨A。
而使用指针后,传递的是地址,相当于直接把一箱凤梨从X地放到Y地,此时凤梨A还是凤梨A,因为只有一箱凤梨,所以如果X地需要用到凤梨还需要从Y地拿回去,也就是说,把Y地的凤梨A榨汁也会影响原来X地的凤梨,即操作形参相当于操作实参。
五、总结
以上就是今天介绍的内容,如果想要实现一个只能输入小数/字母的scanf也可以通过类似方法解决,只需要把int和%d改掉就可以了。