| 函數 | 標準 | 安全性 | 備註 |
gets() | C89~C99 | ❌ 極度危險 | C11 移除 |
fgets() | C89 | ✅ 安全 | 保留換行符,需手動移除 |
gets_s() | C11 Annex K | ✅ 安全 | 需定義 __STDC_WANT_LIB_EXT1__ |
getline() | POSIX | ✅ 安全 | 自動分配記憶體,Linux/Unix 專用 |
推薦方案一:標準 fgets() 包裝
#include
#include
// 安全讀取一行,自動移除換行符
char *safe_gets(char *buf, size_t size) {
if (fgets(buf, size, stdin) == NULL)
return NULL;
// 移除結尾換行符
size_t len = strlen(buf);
if (len > 0 && buf[len-1] == '\n')
buf[len-1] = '\0';
return buf;
}
// 使用範例
int main() {
char str[30];
while (safe_gets(str, sizeof(str))) {
printf("輸入: %s\n", str);
}
}
推薦方案二:動態記憶體版本 (無長度限制)
#include
#include
#include
// 動態擴充緩衝區讀取任意長度行
char *dynamic_gets(void) {
size_t capacity = 128;
size_t len = 0;
char *buf = malloc(capacity);
if (!buf) return NULL;
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
if (len + 1 >= capacity) {
capacity *= 2;
char *new_buf = realloc(buf, capacity);
if (!new_buf) { free(buf); return NULL; }
buf = new_buf;
}
buf[len++] = (char)ch;
}
if (len == 0 && ch == EOF) { free(buf); return NULL; }
buf[len] = '\0';
return buf; // 呼叫者需 free()
}
推薦方案三:固定緩衝區強化版
// 修正原文缺陷:正確處理 EOF、緩衝區滿、輸入殘留
char *const Gets_fixed(char *const array, int maxlen) {
if (!array || maxlen <= 0) return NULL;
int i = 0, ch;
while (i < maxlen - 1) { // 保留空間給 \0
ch = getchar();
if (ch == EOF) {
if (i == 0) return NULL;
break;
}
if (ch == '\n') break;
array[i++] = (char)ch;
}
array[i] = '\0';
// 關鍵:清除輸入緩衝區殘留字元
if (ch != '\n' && ch != EOF)
while ((ch = getchar()) != '\n' && ch != EOF);
return array;
}
原文程式碼缺陷分析
- 未檢查 malloc 失敗後的返回值使用:
if(!str) return 0; 但後續仍操作 str
- 靜態區域變數:
static char* str 導致非重入、執行緒不安全
- 未清理輸入緩衝區:輸入超過
maxlen 時,殘留字元干擾下次讀取
- fflush(stdin) 未定義行為:C 標準僅定義輸出流刷新,輸入流刷新為實作定義
現代最佳實務
// C11 可選邊界檢查介面 (需編譯器支援)
#define __STDC_WANT_LIB_EXT1__ 1
#include
char buf[100];
if (gets_s(buf, sizeof(buf)) == NULL) {
// 處理錯誤或 EOF
}
// 跨平台通用安全模式
#define SAFE_GETS(buf) fgets(buf, sizeof(buf), stdin)
編譯器防護機制
- GCC/Clang:
-Wdeprecated-declarations 警告 gets 棄用
- MSVC:
_CRT_SECURE_NO_WARNINGS 否則編譯錯誤
- Fortify Source:
-D_FORTIFY_SOURCE=2 運行期緩衝區檢查
- Stack Smashing Protector:
-fstack-protector-strong 堆疊金絲雀防護
- 上一篇文章: C語言文件操作函數大全:fopen/fread/fwrite/fseek 等核心 API 深度解析
- 下一篇文章: C語言位運算符完整指南:技巧、應用與經典面試題
Copyright ©
程式碼之家 All Rights Reserved