在 C 语言中,gets() 和 scanf("%s", &s) 都是用来读取字符串的,但它们在行为和使用上有很大的不同。下面是它们的主要区别:
gets() 函数gets() 是一个用于从标准输入读取一行文本的函数,直到遇到换行符 (\n) 或文件结束符 (EOF) 为止。它将整行输入(包括空格)读取并存储在指定的字符数组中。但是,gets() 是不安全的,容易导致缓冲区溢出,因此在现代 C 编程中已不推荐使用,甚至在 C11 标准中被移除。
gets() 会读取整个输入,包括空格,直到遇到换行符为止。gets() 不会检查目标数组的大小,这就可能导致缓冲区溢出问题。例如,如果用户输入的内容超过了目标数组的大小,就会覆盖数组以外的内存区域,导致程序崩溃或出现未定义行为。#include <stdio.h>
int main() {
char s[100];
gets(s); // 不安全
printf("You entered: %s\n", s);
return 0;
}scanf("%s", &s) 函数scanf() 是一个用于格式化输入的标准函数,scanf("%s", &s) 读取字符串,直到遇到空白字符(空格、换行符或制表符)。与 gets() 不同的是,scanf() 会跳过空白字符并读取第一个非空白的字符串。
scanf("%s", s) 会读取并存储一个由非空白字符组成的字符串,遇到空格、换行符或制表符时停止读取。scanf() 本身也没有进行内存边界检查,如果输入的字符串太长,会导致缓冲区溢出。因此,常常需要限制读取字符的最大数量,防止这种情况发生。#include <stdio.h>
int main() {
char s[100];
scanf("%s", s); // 读取直到第一个空白字符
printf("You entered: %s\n", s);
return 0;
}scanf("%s", s) 只读取单词,空格被当作分隔符,后续的字符会被当作新的一部分进行读取。例如,输入 "Hello World" 时,scanf("%s", s) 只会读取 "Hello",而 "World" 会留在输入缓冲区中。| 特性 | gets() | scanf("%s", s) |
|---|---|---|
| 读取行为 | 读取整行(包括空格)直到换行符 | 读取直到第一个空白字符(空格、换行符、制表符) |
| 缓冲区溢出问题 | 没有检查缓冲区大小,容易溢出 | 没有自动检查缓冲区大小,容易溢出 |
| 空白字符处理 | 允许空格、制表符、换行符作为输入的一部分 | 遇到空白字符时停止读取(空格、换行符、制表符) |
| 安全性 | 不安全(已废弃,C11 中已移除) | 相对安全,但需要指定最大宽度限制以防溢出 |
| 返回值 | 返回读取的字符串 | 返回成功读取的项数 |
由于 gets() 和 scanf("%s", s) 都可能导致缓冲区溢出,因此你应该采取措施来防止这种情况。对于 scanf,可以通过限制输入的最大字符数来避免溢出:
scanf 限制输入的最大字符数:scanf("%99s", s); // 限制最多读取 99 个字符(保留一个字符位置给结束符 '\0')fgets() 代替 gets():fgets() 是更安全的选择,因为它可以指定读取的最大字符数,从而避免溢出。它也会保留换行符,因此你可能需要去掉换行符。
#include <stdio.h>
int main() {
char s[100];
fgets(s, sizeof(s), stdin); // 读取一行并确保不会溢出
printf("You entered: %s\n", s);
return 0;
}fgets() 读取时会保留换行符。如果你想去除换行符,可以手动处理:
s[strcspn(s, "\n")] = '\0'; // 去掉换行符gets(): 已废弃,不安全,容易导致缓冲区溢出。scanf("%s", s): 只读取单词(遇到空格、换行符停止),也没有边界检查,容易导致溢出。使用时最好加上宽度限制。fgets(): 安全,建议用于读取字符串,允许输入包含空格的整行文本,并且可以限制读取的字符数,从而防止溢出。