分享|c语言gets读取字符串和scanf读取字符串的区别
匿名用户
666
2025.01.03
2025.01.03
发布于 湖南

在 C 语言中,gets()scanf("%s", &s) 都是用来读取字符串的,但它们在行为和使用上有很大的不同。下面是它们的主要区别:

1. 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;
}

缺点:

  • 没有边界检查,可能会导致缓冲区溢出
  • 已被 C11 标准废弃,现代编译器会警告你不要使用它。

2. 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" 会留在输入缓冲区中。

3. 主要区别总结

特性gets()scanf("%s", s)
读取行为读取整行(包括空格)直到换行符读取直到第一个空白字符(空格、换行符、制表符)
缓冲区溢出问题没有检查缓冲区大小,容易溢出没有自动检查缓冲区大小,容易溢出
空白字符处理允许空格、制表符、换行符作为输入的一部分遇到空白字符时停止读取(空格、换行符、制表符)
安全性不安全(已废弃,C11 中已移除)相对安全,但需要指定最大宽度限制以防溢出
返回值返回读取的字符串返回成功读取的项数

4. 避免缓冲区溢出

由于 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';  // 去掉换行符

5. 总结

  • gets(): 已废弃,不安全,容易导致缓冲区溢出。
  • scanf("%s", s): 只读取单词(遇到空格、换行符停止),也没有边界检查,容易导致溢出。使用时最好加上宽度限制。
  • fgets(): 安全,建议用于读取字符串,允许输入包含空格的整行文本,并且可以限制读取的字符数,从而防止溢出。
评论 (0)