关于gets()与scanf()输入字符串与\0,\n,空格之间的问题

本文详细介绍了C语言中输入字符串时gets()和scanf()函数的不同处理方式。gets()函数遇到空格会将其视为普通字符,而scanf()则在遇到空格后停止读取。对于回车符 ,gets()会将其丢弃,而scanf()会保留。此外,手动输入的会被编译器解析为两个字符。在使用这两个函数时,需要注意输入缓冲区的清理,特别是scanf()可能导致的未读取的 。最后,编译器会在字符串末尾自动添加。

我们都知道输入字符串的话,用gets()函数与scanf()加%s的话都是可以的。同时,一个字符串的结尾默认有一个\0也是老生常谈。

空格

gets()

1. 当gets()碰到空格时就把它当成一个普通的字符来看,没有任何特殊之处可言。

scanf()

1. 如果再输入过程中间有空格的话,那么它只读取空格前面的字符,碰到空格的话就到此为止了,接下来不再下去了。

2. 就算是最后输入空格,也是一样,反正就是碰到空格的话就停下来不再继续读取,同时这个空格这个字符是不包括在内的。

接下来对于\n与\0,需要知道的是:你手动输入的\0与\n与真正的字符串末尾的\0、按下一个回车键导致往输入缓冲区里面放进去的\n这两者的话是有区别的。对于你手动输入的那些,编译器会把它看成两个字符

\n

1. 我们都知道,当敲一下回车的时候,就相当于输入缓冲区里面放入一个\n.

2. 但是当我们自己在输入中的时候,自己手动输入的一个\n,编译器不会把这个\n当成回车的那个,还是会把它解读成两个字符,这个对于gets与scanf两者相同。

两个注意点:

1. 对于最后输入回车然后放到输入缓冲区里面的那个\n,两者的处理方式就有不同。scanf()是读取那个之前的字符,然后那个\n就仍然留在输入缓冲区里面,这也因此导致可能需要清理输入缓冲区。而gets()会把最后敲进去的那个\n自动给扔出来。

2. 对于scanf输入完之后,如果没有清空缓存区的话,这时候输入缓冲区一个字符就是\n,无论接下来有gets函数还是scanf读取新的内容,首先不可避免的会先读到\n,一旦读到这个“货真价实”的\n,那么就直接回车\换行了。

 

\0 

1. 通过监视也不难发现,当在输入过程中,自己手动输入一个\0,编译器会把它解读成两个字符。

一个注意点:

1. 我们都知道,字符串的末尾默认带有一个\0,但是当从输入缓冲区里面读取字符串的时候,人为的并没有输入\0,但是从上面那么多的监视当中不难发现,编译器会在最屁股后面自动会补上一个\0。

<think>我们正在讨论C语言getsscanf函数在输入字符串时的区别。 首先,让我们回顾一下这两个函数: 1. gets函数: - 原型:char *gets(char *str); - 功能:从标准输入(stdin)读取一行,并将其存储到str所指向的字符串中。它会一直读取,直到遇到换行符(由Enter键产生)或文件结束符(EOF)为止。 - 换行符会被丢弃,不会存储在字符串中,然后在字符串末尾自动添加空字符('\0')。 2. scanf函数: - 当使用%s格式时,scanf用于读取字符串。 - 原型:int scanf(const char *format, ...); - 使用示例:scanf("%s", str); - 功能:它会跳过前导空白字符(如空格、制表符、换行符),然后读取非空白字符,直到遇到空白字符或文件结束符为止。然后,它会自动在末尾添加空字符。 主要区别: a) 空格处理: - gets可以读取包含空格的整行(直到换行符),因此它读取的字符串可以包含空格。 - scanf使用%s时,遇到空格就会停止读取,因此它不能读取包含空格字符串(只能读取一个单词)。 b) 缓冲区溢出风险: - gets函数不检查目标数组的容量,如果输入的行过长,会导致缓冲区溢出,这是一个严重的安全问题。因此,在C99标准中已被弃用,在C11标准中已被移除。 - scanf虽然也有风险,但可以通过指定字段宽度来避免(尽管很多程序员没有这样做)。例如,使用`scanf("%10s", str);`可以确保最多读取10字符(因为还要一个位置放'\0',所以实际最多存储9个字符)。如果不指定宽度,同样有溢出风险。 c) 返回值: - gets在成功时返回传入的指针,失败或遇到文件结束符时返回NULL。 - scanf返回成功匹配和赋值的输入项数,如果失败或遇到文件结束符,则返回EOF。 d) 换行符处理: - gets会读取并丢弃换行符(换行符不会放入字符串,而是替换为'\0')。 - scanf使用%s时,不会读取换行符,换行符会留在输入缓冲区中。这可能会影响后续的输入读取。 由于gets函数的不安全性,推荐使用fgets函数来代替。fgets可以指定最大读取字符数,因此更安全。 下面给出两个例子: 示例1:使用gets(注意:不推荐使用) ```c #include <stdio.h> int main() { char str[100]; printf("Enter a string: "); gets(str); // 输入整行,包括空格,但存在溢出风险 printf("You entered: %s\n", str); return 0; } ``` 示例2:使用scanf(只能读取一个单词) ```c #include <stdio.h> int main() { char str[100]; printf("Enter a string: "); scanf("%s", str); // 遇到空格就停止 printf("You entered: %s\n", str); return 0; } ``` 示例3:安全地使用fgets替代gets ```c #include <stdio.h> int main() { char str[100]; printf("Enter a string: "); fgets(str, sizeof(str), stdin); // 安全,指定了缓冲区大小 // 注意:fgets会保留换行符(如果有的话),我们可以手动去掉 int len = strlen(str); if (len > 0 && str[len-1] == '\n') { str[len-1] = '\0'; // 去掉换行符 } printf("You entered: %s\n", str); return 0; } ``` 总结: - 避免使用gets,因为它不安全。 - 如果只需要读取一个单词(无空格),可以使用scanf,但要注意限制宽度以避免溢出。 - 如果要读取整行(包含空格),推荐使用fgets并处理掉末尾的换行符(如果有)。 §§相关问题§§: 1. C语言中为什么gets函数被弃用? 2. fgetsgets有什么区别? 3. 如何安全地使用scanf读取字符串而不导致缓冲区溢出? 4. 在C语言中,如何处理输入缓冲区中残留的换行符? </think>### C语言中`gets`和`scanf`输入字符串的区别 #### 核心区别: 1. **空格处理能力** - `gets()` 读取整行(包括空格),直到遇到换行符 - `scanf("%s", ...)` 遇到空格/换行会终止输入 2. **安全性** - `gets()` 不检查缓冲区边界,存在溢出风险 - `scanf()` 可通过字段宽度限制预防溢出(如`%10s`) 3. **行尾处理** - `gets()` 丢弃换行符 - `scanf()` 保留空白字符输入缓冲区中 --- ### 代码示例说明 #### 1. `gets()` 示例(危险!) ```c #include <stdio.h> int main() { char buffer[5]; // 仅容纳4字符+结尾符 printf("Enter text: "); gets(buffer); // 输入超过4字符将溢出! printf("You entered: '%s'\n", buffer); return 0; } ``` **风险**:输入 `"12345"` 会覆盖临近内存,可能导致程序崩溃。 #### 2. 安全的 `scanf()` 用法 ```c #include <stdio.h> int main() { char buffer[5]; printf("Enter text: "); scanf("%4s", buffer); // 限制读取4字符 printf("Safe input: '%s'\n", buffer); // 清空输入缓冲区 int c; while ((c = getchar()) != '\n' && c != EOF); return 0; } ``` **关键点**: - `%4s` 确保最多读取4字符 - `while` 循环清除缓冲区残余字符 --- ### 推荐替代方案:使用 `fgets()` ```c #include <stdio.h> #include <string.h> int main() { char buffer[5]; printf("Enter text: "); fgets(buffer, sizeof(buffer), stdin); // 安全限定长度 // 移除可能的换行符 if (strlen(buffer) > 0 && buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = '\0'; printf("Safe with fgets: '%s'\n", buffer); return 0; } ``` **优势**: - 明确指定缓冲区大小 - 自动处理换行符(需手动移除) - 无溢出风险
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

立志成为软件工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值