你不知道的scanf函数的那些事

前言

当需要从标准输入(键盘stdin)读取数据时,C语言中的scanf函数是一种常用的输入函数。scanf函数允许程序员指定输入数据的类型和格式,并将输入数据存储到指定的变量中。虽然它很方便简单,但是在使用时,我们仍会犯很多细节上的错误!
今天我来大家详细了解scanf函数的本源
各位我们发车了!
在这里插入图片描述

1.基本语法

scanf函数的原型为:

int scanf(const char *format, ...);

其中,第一个参数format是格式化字符串,用于指定输入的格式。从第二个参数开始,每个参数都是一个指向变量的指针,用于存储读取到的数据。

在格式化字符串中,可以使用以下格式指定输入的类型:

格式字符 描述
%d 读入一个整数,可以是十进制、八进制或十六进制形式。
%u 读入一个无符号整数,可以是十进制、八进制或十六进制形式。
%f 读入一个浮点数,可以是普通形式或指数形式。
%lf 读入一个双精度浮点数,可以是普通形式或指数形式。
%c 读入一个字符。
%s 读入一个字符串,字符串以空格、制表符或换行符结束。
%p 读入一个指针。
%i 读入一个整数,可以是十进制、八进制或十六进制形式。
%o 读入一个八进制整数。
%x 读入一个十六进制整数。
%e 读入一个浮点数,可以是普通形式或指数形式。
%g 读入一个浮点数,可以是普通形式或指数形式,自动选择%f或%e格式输出。
%a 读入一个十六进制浮点数。
%hhn 读入一个字符,将字符的ASCII码值存储到指定的变量中。
%hhu 读入一个无符号字符。
%hhd 读入一个有符号字符。
%n 将已经读入的字符数存储到指定的变量中,可以用于计算输入数据的长度。
%m 为指定的字符串变量分配内存空间,并读入字符串。

我们还可以使用修饰符指定输入的长度和精度。

格式字符 描述
%d, %i, %o, %u, %x, %X %0n(数字n表示最小字段宽度,如果数据不够n位就在左边填充0)
%f, %e, %E %m.n(数字m表示最小字段宽度,n表示小数点后的位数)
%g, %G %m.n(数字m表示最小字段宽度,n表示有效数字的位数)

例如,%05d表示将一个整数输出为5位宽度,不足5位用0在左边填充;%10.2f表示将一个浮点数输出为10位宽度,小数点后保留2位小数;%8.3g表示将一个数字输出为8位宽度,保留3位有效数字。

2.返回值

scanf函数是有返回值的,scanf函数的返回值是成功读取的参数数量。例如,如果成功读取了一个整数,则返回值为1。如果成功读取了两个整数,则返回值为2。如果读取失败或者到达了输入流的末尾,则返回值为EOF(-1)。

在实际编程中,我们可以利用scanf函数的返回值来判断输入是否成功。例如,下面的代码中,我们使用scanf函数读取一个整数,如果读取失败,则提示用户重新输入:

int num;

while(scanf("%d", &num) != 1) {
    
    
    printf("输入错误,请重新输入:");
    while(getchar() != '\n');  //清空缓冲区
}

3.输入缓冲区

3.1 什么是输入缓冲区

输入缓冲区是计算机中用于存储待处理输入数据的一种内存区域。在C语言中,当程序需要从标准输入设备(如键盘)读取数据时,输入数据首先被暂时存储在输入缓冲区中,等待程序使用各种输入函数(如scanf、fgets、getchar等)来读取。

输入缓冲区的大小和实现方式可能因不同的操作系统和编译器而有所不同,但通常情况下,输入缓冲区的大小是固定的,一般为几千字节到几万字节不等。当输入缓冲区已满时,后续输入数据将无法存储,直到程序读取部分或全部输入数据后,输入缓冲区才能继续接收输入数据。

输入缓冲区的存在是为了提高程序读取输入数据的效率。因为输入设备(如键盘)和计算机之间的通信速度较慢,而程序往往需要对输入数据进行一些处理才能继续运行,如果每次输入数据都要等待处理完成才能继续输入下一组数据,那么程序的效率会大大降低。

需要注意的是,输入缓冲区的存在也可能会导致一些问题,例如当输入数据格式不正确时,输入数据将一直留在输入缓冲区中,导致后续的输入操作出现错误。为了避免这种情况,程序需要对输入数据进行适当的检查和处理,以保证输入数据的正确性。

3.2 具体使用

当我们使用scanf函数从标准输入中读取数据时,输入数据会先被存储到输入缓冲区中,然后再从缓冲区中读取数据并保存到指定的变量中。但是,如果在读取之前没有清空输入缓冲区,就可能导致缓冲区中的残留数据对后续的输入操作产生影响。这种情况通常是由于输入数据的类型与scanf函数要求的类型不匹配,或者输入数据中包含了多余的字符或换行符等原因导致的。

int main()
{
    
    
	int num;
	char ch;

	scanf("%d", &num);
	scanf("%c", &ch);
	printf("%d\n", num);
	printf("%c\n", ch);
	printf("------------");


}

在这里插入图片描述

如果我们在输入第一个整数后直接按下回车键,那么回车字符就会被留在输入缓冲区中,成为下一个scanf函数的输入。由于第二个scanf函数要求读取一个字符,因此它会从输入缓冲区中读取回车字符并将其保存到变量ch中,而不是我们期望的字符。如上图所示。
这种情况可能会导致程序出现不可预料的行为,甚至崩溃。

那么我们该如何避免这种情况呢?

在这之前,我们先来了解getchar()函数的用法。

getchar是C语言中常用的一个函数,用于从标准输入设备(一般为键盘)读取一个字符。
它的函数原型为:

int getchar(void);

getchar函数的返回值是一个整数,表示读入的字符的ASCII码值。

如果读取失败(例如读到文件末尾),则返回EOF(End Of File)。

下面是一个简单的示例,演示如何使用getchar函数从标准输入读取字符并输出:

int main() {
    
    
    int c;
    printf("请输入一个字符:");
    c = getchar();
    printf("您输入的字符是:%c\n", c);
    return 0;
}

在上面的例子中,使用getchar函数读取用户输入的字符,并将读入的字符赋值给变量c。

需要注意的是,getchar函数每次只能读取一个字符,并且读取到的字符包括换行符(‘\n’)。如果需要读取多个字符,可以使用循环来多次调用getchar函数,直到读取到需要的字符为止。另外,为了避免输入缓冲区中的残留字符影响下一次读取,可以使用类似清空输入缓冲区的方法,将输入缓冲区中的所有残留字符都读取并丢弃。

在了解getchar函数的用法后,现在我们就可以解决scanf函数输入缓冲区的问题了!

我们可以在读取字符之前先清空输入缓冲区。可以使用如下代码来清空输入缓冲区:

while(getchar() != '\n');

这个代码会一直从输入缓冲区中读取字符,直到读取到换行符为止。
这样就可以将输入缓冲区中的所有残留数据清空。

修改后的代码如下:

int main() {
    
    
    int num;
    char ch;

    printf("请输入一个整数:");
    scanf("%d", &num);
    while (getchar() != '\n'); // 清空输入缓冲区

    printf("请输入一个字符:");
    scanf("%c", &ch);
    while (getchar() != '\n'); // 清空输入缓冲区

    printf("您输入的整数是:%d\n", num);
    printf("您输入的字符是:%c\n", ch);
    printf("------------\n");

    return 0;
}

在这里插入图片描述
这样是不是就达到我们的预期了呢!

今天的知识分享就到这里啦!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_69218005/article/details/130188180