C语言gets函数详解:“输入黑洞”

一句话理解 gets

「gets 就像一个不设防的‘输入黑洞’,贪婪吞噬用户输入直到换行,但极易引发缓冲区溢出灾难!」
( 注意:gets 已从C11标准中移除,绝对禁止在实际开发中使用!以下内容仅供学习历史代码参考。)


函数原型

#include 
char *gets(char *str);  // 危险!已被废弃!

入口参数

参数

类型

比喻解释

str

char*

存放输入的「脆玻璃瓶」(字符数组)

返回参数

返回值

含义

char*

成功时返回 str 指针

NULL

输入失败或遇到EOF


灾难代码示例

场景1:缓冲区溢出导致程序崩溃

#include 

int main() {
    char fragile_bottle[5];  // 只能装4字符+1个\0
    
    printf("输入你的名字:");
    gets(fragile_bottle);    //  危险操作!

    printf("你好,%s!\n", fragile_bottle);
    return 0;
}

输入测试

输入:Alexander  
输出:你好,Alexander!  
(实际已溢出,可能触发段错误/修改其他内存)

场景2:安全漏洞演示(密码绕过)

#include 
#include 

int check_password() {
    char password[8] = "secret";
    char input[8];
    
    printf("输入密码:");
    gets(input);  //  输入超长可覆盖password数组
    
    return strcmp(input, password) == 0;
}

int main() {
    if (check_password()) {
        printf(" 登录成功");
    } else {
        printf(" 密码错误");
    }
    return 0;
}

攻击测试

输入:aaaaaaaaaaaaaaa  
(溢出input数组,覆盖password为aaa...)
输出: 登录成功  

安全替代方案:fgets

#include 
#include 

void safe_input(char *buf, int size) {
    fgets(buf, size, stdin);          //  安全读取
    buf[strcspn(buf, "\n")] = '\0';   // 去除换行符
}

int main() {
    char safe_bottle[5];
    printf("输入你的名字:");
    safe_input(safe_bottle, sizeof(safe_bottle));
    
    printf("你好,%s!\n", safe_bottle);
    return 0;
}

输入测试

输入:Alexander  
实际存储:"Alex"(自动截断,避免溢出)

技术解剖

特性

gets

fgets

缓冲区检查

明确指定最大长度

换行符处理

丢弃

保留并存入缓冲区

安全性

极易引发溢出攻击

安全可靠


历史教训

  • 1988年莫里斯蠕虫病毒:利用 gets 的溢出漏洞感染了全球10%的互联网计算机。
  • CWE-242:被列为「危险函数黑名单」头号危险函数。
  • 现代编译器态度
# GCC编译警告
warning: the `gets' function is dangerous and should not be used.

总结

  • 像定时炸弹:gets 是C语言历史上最臭名昭著的函数之一。
  • 必须遵守
    1 永远不要使用 gets
    2 用 fgets 或 getline 替代
    3 开启编译器安全选项(如 -Wall -Werror)
原文链接:,转发请注明来源!