首页 > 编程笔记 > C语言笔记(精华版)

C语言gets函数的用法(非常详细和全面)

C语言 gets() 函数用于从标准输入(通常是键盘)读取一行字符串。gets() 的主要作用是读取用户输入的一行文本,并将其存储到指定的字符数组中。

这个函数在早期的C语言编程中经常被使用,但由于其存在严重的安全隐患,现在已经不推荐使用。

gets() 函数的核心作用是从标准输入读取字符,直到遇到换行符\n或文件结束符EOF为止。gets() 会将读取到的字符存储到指定的字符数组中,并在字符串末尾自动添加空字符\0作为结束标志。这个函数会丢弃输入中的换行符,不将其存储在目标数组中。


举个例子,假设用户输入了 "Hello, World!",gets() 函数会读取这个字符串并将其存储到指定的数组中,最终数组中的内容将是 "Hello, World!\0"。


然而,gets() 函数的一个重大缺陷是它不会检查目标数组的大小,这意味着如果用户输入的字符串长度超过了数组的容量,gets() 函数会继续往数组后面的内存空间写入数据,导致缓冲区溢出。这种行为可能会覆盖其他变量的值,甚至可能被恶意利用来执行未经授权的代码。

gets() 函数的用法

gets() 函数的位于 <stdio.h> 头文件中,它的原型如下所示:

char *gets(char *str);

gets() 函数只接受一个参数,也就是 str。str 一个指向 char 类型的指针,用于存储读取到的字符串,这个指针通常指向一个预先分配好的字符数组。
 

gets() 函数的返回值有两种情况:


下面是一个使用 gets() 函数的简单示例:

#include <stdio.h>

int main() {
    char name[50];
    printf("请输入你的名字: ");
    gets(name);
    printf("你好,%s!\n", name);
    return 0;
}

在这个例子中,我们声明了一个可以存储 50 个字符的数组 name。gets() 函数从标准输入读取用户输入的字符串,并将其存储在 name 数组中。然后,我们使用 printf() 函数打印欢迎消息。


运行这段代码,可能会得到如下输出:

请输入你的名字: John Doe
你好,John Doe!

gets() 函数的安全问题

尽管 gets() 函数使用简单,但它存在严重的安全隐患,如果用户输入的字符串长度超过了数组的容量,就会发生缓冲区溢出。例如,在上面的示例中,如果用户输入超过 49 个字符(考虑到结尾的空字符),就会导致缓冲区溢出。


考虑以下情况:

#include <stdio.h>

int main() {
    char name[10];
    int important_data = 42;
    
    printf("请输入你的名字: ");
    gets(name);
    
    printf("你好,%s!\n", name);
    printf("重要数据: %d\n", important_data);
    
    return 0;
}

如果用户输入一个长度超过 9 的字符串,例如 "abcdefghijklmnop",gets() 函数会继续往 name 数组后面的内存空间写入数据,可能会覆盖 important_data 的值。
 

由于 gets() 函数的安全问题,现代C语言编程中已经不再推荐使用它。gets() 的替代方案包括:


下面是使用 fgets() 函数的安全版本示例:

#include <stdio.h>
#include <string.h>

int main() {
    char name[50];
    printf("请输入你的名字: ");
    if (fgets(name, sizeof(name), stdin) != NULL) {
        name[strcspn(name, "\n")] = 0; // 移除换行符
        printf("你好,%s!\n", name);
    }
    return 0;
}

在这个例子中,fgets() 函数限制了最大读取字符数,有效防止了缓冲区溢出。同时,我们使用 strcspn() 函数来移除 fgets() 可能读取的换行符。


下面是使用 gets_s() 的示例代码:

#include 
#define MAX_LENGTH 100

int main() {
    char input[MAX_LENGTH];
    if (gets_s(input, sizeof(input)) != NULL) {
        printf("您输入的是:%s\n", input);
    } else {
        printf("读取输入时发生错误\n");
    }
    return 0;
}

值得注意的是,gets_s() 函数并不是所有编译器都支持,因为它只是 C11 标准的可选部分或者扩展部分,而不是核心部分。如果你的编译器不支持 gets_s(),可以考虑使用其他替代方案。

总结

gets() 函数虽然使用简单,但由于其固有的安全风险,在现代C语言编程中应该避免使用。作为替代,应该使用更安全的函数如 fgets()、scanf()、getline() 或者 gets_s()。这些函数提供了更好的输入控制,可以有效防止缓冲区溢出等安全问题。

相关文章