gets、getwd 是 C 语言两个经典高危废弃函数,核心问题一致:没有缓冲区长度校验,会造成内存越界、非法内存访问、程序崩溃,正式工程、考试、项目中一律禁用。
一、gets 函数(字符串输入越界)
1. 函数原型
#include <stdio.h> char *gets(char *s);
2. 基础用法
char str[10]; gets(str); // 数组名等价于 &str[0],传数组首地址3. 核心特性
1. 可以读取空格、TAB 等空白字符,仅回车\n结束输入;
2. 自动丢弃换行符,不会把 \n 存入数组,自动补\0收尾;
3. 和 scanf 区别:scanf 遇到空格、TAB、回车就终止,无法读取带空格字符串,gets 可以。
4. 致命漏洞(废弃原因)
gets没有长度参数,完全不检查数组容量。
当用户输入字符串超过数组最大长度,函数会持续向后写入内存,造成:数组越界、篡改相邻变量、非法内存访问、程序段错误崩溃。
C11 标准已彻底删除 gets 函数。
5. 安全替代:fgets
函数原型
char *fgets(char *buf, int size, FILE *stream);参数详解(通俗直白、考试原话)
- buf:字符缓冲区数组,用来存放读取到的字符串;
- size:缓冲区最大长度,传入 sizeof(buf),是防越界的核心,限制最多读取的字节数;
- stream:指定数据的读取来源
stdin 全称标准输入流,C语言默认绑定键盘设备。
直白话: fgets 是通用函数,既能读文件、也能读键盘;
写 stdin = 告诉程序:这次不从文件读,从键盘读取用户输入。
控制台键盘输入场景,第三参数固定写 stdin。
❌ 错误代码(gets 越界漏洞)
char buf[10]; gets(buf); // 无长度限制,输入超过9个字符直接越界✅ 正确代码(fgets 安全写法)
char buf[128]; fgets(buf, sizeof(buf), stdin);6. fgets 与 gets 关键区别
1. 保留优点:同样支持读取空格、TAB;
2. 修复漏洞:带长度限制,超长自动截断,绝不越界;
3. 唯一不同:fgets 会把回车\n读入数组缓冲区。
7. 适用场景
- gets:全线禁用,存在高危越界漏洞;
- fgets:读取带空格的键盘字符串、文本数据、配置文件内容;
- scanf:仅适合读取无空格的数字、单个单词。
二、getwd 函数(工作路径越界)
1. 核心漏洞
getwd 仅接收数组指针,无长度校验参数。
函数默认按系统最大路径长度写入内存,若自定义数组空间过小,会直接溢出、非法内存访问、程序崩溃,POSIX.1-2008 标准已废弃。
2. 安全替代:getcwd
函数原型
char *getcwd(char *buf, size_t size);参数详解
- buf:存储当前工作路径的字符数组;
- size:手动指定数组真实长度,限制最大写入字节数。
防越界原理
若当前路径字符串长度大于 size-1,函数直接返回 NULL、报错,不会写入溢出内存,从根源杜绝越界。
返回值
- 成功:返回路径字符串首地址;
- 失败:返回 NULL,自动设置错误码 errno。
❌ 错误代码(getwd 越界漏洞)
char path[32]; getwd(path); // 路径过长直接越界,触发段错误✅ 正确代码(getcwd 安全写法)
char path[128]; getcwd(path, sizeof(path)); // 带长度限制,超长报错不越界 printf("当前路径:%s\n", path);3. 进阶用法:get_current_dir_name
无需手动定义数组、无需预估缓冲区大小,函数内部自动 malloc 足够内存存储绝对路径。
注意:使用后必须 free 释放内存,防止内存泄漏;必须前置定义宏#define _GNU_SOURCE,且宏要写在头文件之前。
#define _GNU_SOURCE #include <unistd.h> #include <stdio.h> #include <stdlib.h> int main() { char *path = get_current_dir_name(); if(path != NULL) { printf("当前路径:%s\n", path); free(path); } return 0; }4. 适用场景
getwd:全线禁用;
getcwd:程序初始化获取工作目录、拼接日志路径、定位配置文件、目录权限校验。
三、核心总结
- gets / getwd 共性:无长度参数、无边界校验,必然内存越界,标准废弃;
- fgets / getcwd 共性:强制携带长度参数,超长截断/报错,杜绝非法内存访问;
- 所有缓冲区读写,必须指定有效长度,禁止无边界操作。