【c语言初阶】一个只能输入整数的scanf

一、前言

最近刚好在写一个仿登陆系统,需要多次用到“只能输入整型数据”的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改掉就可以了。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值