浅谈 scanf(),gets() 区别

    技术2025-09-08  32

    在平时编程过程中,常常会遇到一些莫名其妙的区别。就像下面两张图一样。 这两张图我们只是简单地输入了几个数据,但是结果发现有个输入中间有空格,但有个没有。这主要是 scanf("%s",ch); 和 gets(ch); 之间的区别。

    在最开始先列一下我们要讨论的几种类型。

    scanf("%d",&xxx); // 从输入缓冲区第一个非空白符读取,读到下一个非数字字符 scanf("%c",&xxx); // 从输入缓冲区读取第一个字符,不管是不是空白符 scanf("%s",xxx); // 从输入缓冲区第一个非空白符读取,读到下一个空白符 gets(xxx); // 从输入缓冲区第一个字符读取,读到换行符为止

    我们在谈论这些之前,先初步了解一下输入缓冲区。 先上个链接 缓冲区 在上面的链接中谈到了缓冲区分为几种类型,我们在这里输入的是行缓冲。当输入遇到换行时才进行操作。比如下面这个例子。

    #include<stdio.h> int main() { int a[5],i; for(i=0;i<5;i++){ scanf("%d",&a[i]); printf("%d ",a[i]); } return 0; }

    这是一个很简单的例子,但有一点特殊的地方。在代码里我输入一个数之后立马就将那个数输出了,但是我运行的时候并不是这样。 这是我用空格分开输入时的输出状态。它等到我全部都输入完之后才输出。而我换一种方式输入就不一样。 当我每输入一个数之后我是用换行符将他们分割时,每输入一个紧接着就会输出一个数。

    为什么会有这种效果呢,就是上面我们所说的 “行缓冲遇到换行时才进行操作”。 第一种,我一直是以空格的形式输入的。一开始没输入的时候有个scanf需要数据,他就等着我往输入缓冲区中输入数据。但在没有换行之前它依然没有执行程序,因为我还在往输入缓冲区中输入数据,直到我按下了那个换行符,程序才开始从输入缓冲区中读取数据交给等着要数据的变量。因为我已经把所有数据都送到输入缓存区里了,程序要数据的时候直接从输入缓存区中读取数据即可。所以按下回车之后就将要输出的数据一块输出了。

    而第二种不一样。我们是以换行符分割每个输入的,输入 a[0] 后换行,程序就去输入缓存区里读取数据,读完后执行下一个语句,就输出了 a[0] 。接下来也是同样的操作。

    到现在为止我们对输入缓冲区有了初步的了解,我们就可以来分析上面那几种类型啦!

    第一种: scanf("%d",&xxx);

    这里用的是 %d ,%f %ll %lu %l %ld 都是这一种。程序运行到这个输入语句时就去输入缓冲区内找数据。若是缓冲区中没有足够的数据,就会等待你往里面输入数据。 而 %d 会从第一个非空白符开始读起,读到下一个非数字符。如下面程序。

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

    当我们输入一个不太常规的数据时,程序从输入缓冲区中读取数据。遇到空白符跳过,找到第一个数字符开始读取,读到第一个非数字符。所以程序将 2313 送给 num 。送完之后,输入缓冲区中到后面那个3包括他及其之前的数据都被清空了,之后的数据都保留下来了(比如这里的k)。所以紧接着输入 ch 时就将 k 送给 ch。

    如果数字接下来是一个空格符也会照样接下。 这就是我们接下来要说的 %c 的输入方式。

    第二种: scanf("%c",&xxx);

    由上面我们已经知道,在输入的数据是 %c 时,不管是不是空白符他都会照接无误。这点 getchar( ); 也是这样。

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

    他们就不会像之前那样要等待一个非空白符的出现。不管是什么字符,他们都会读取。

    第三种: scanf("%s",xxx);

    %s 用于读取一个字符串,它从第一个非空白符读到下一个空白符。

    #include<stdio.h> int main() { char ch[20],sh; scanf("%s",ch); sh = getchar(); printf("%s||%c||",ch,sh); return 0; }

    我们在输入字母之前输入了一些空白符,但是 %s 并不会去读取它,他会跳过他们去寻找它的非空白符。要注意的是,它读完字符串后将字符串及其之前的数据全部从输入缓冲区清除后,分割它的空白符并不会从输入缓冲区清除掉。比如这里的空格符,当我们将字符串下一个字符读入到 sh 中发现 sh 存储的是一个空格符,就是分割 %s 的那个空格。这也验证了刚刚说的不会将空白符清除。

    而 gets(); 和他不一样

    第四种:gets(xxx);

    #include<stdio.h> int main() { char ch[20],sh; gets(ch); sh = getchar(); puts(ch); printf("||%c||",sh); return 0; }

    控制台发生的一切似乎有点奇妙,我们来分析一下。 首先我们在一开始输入了空格符接着输入了一些字母符,然后按回车,程序没反应,我再输入了一个回车就有反应了。 我们在输出字母前输入了些空格符,可以看出 gets 从输入缓冲区中读取数据时不会跳过空格符和制表符,这点和 %s 不一样。 还有一点不一样的是,若是 %s 我们按下回车时程序就会给我们反应,它会将这个回车送给 sh ,但这里显然不一样。我们在按下第一个回车后它并没有反应,因为它读取的数据还不够,还在等我们输入。哪个数据没有被赋值呢? sh 。在这里在按下第一个换行符时 sh 并没有读取它,它读取到了我们按下的第二个换行符,所以输出的时候才会发生两个 || 在不同行的情况,因为他们之间的 sh 是我们第二次输入的那个换行符。 为什么会这样呢?因为 %s 在读取到空白符时将那个空白符返回到了输入缓冲区里,再在那个字符串后自动补上了 ‘\0’ ,而 gets 并没有将换行符送回到输入缓冲区,它直接将换行符 ‘\n’ 转变为 ‘\0’ 添加到了字符串末尾, 所以第一个换行符之后输入缓冲区中没有数据可供 sh 读取的了。

    %s 和 gets 在这里有两个不一样:

    %s 不会读取最开始的空白符,gets 会。%s 读取结束后会将空白符送回给输入缓冲区,但是 gets 直接将 ‘\n’ 转换成 ‘\0’ ,不再送回给输入缓冲区。 当然他们还有别的区别,比如 gets 只有遇到换行符才结束输入, %s 遇到空白符就会。

    以上就是这几种输入方式细微的区别啦。欢迎大家指正和补充。

    Processed: 0.009, SQL: 9