fgets 是一个常用的标准库函数,用于从文件或标准输入(如键盘)中读取一行字符串。它的主要特点是安全读取,可以防止缓冲区溢出(buffer overflow),相较于 gets 更安全。
1. fgets 函数原型
char *fgets(char *str, int n, FILE *stream);
参数说明
|
参数 |
说明 |
|
|
用于存储读取数据的字符数组(缓冲区)。 |
|
|
最多读取 |
|
|
输入流,可以是文件指针(如 |
返回值
- 成功:返回
str(即传入的缓冲区指针)。 - 失败或到达文件末尾(EOF):返回
NULL。
2. fgets 的特点
(1)读取一行(直到遇到 \n 或 EOF)
- 如果输入行长度 ≤
n-1,则读取整行(包括\n)。 - 如果输入行长度 >
n-1,则只读取前n-1个字符(剩余部分留在缓冲区,下次读取)。
(2)自动添加 \0 终止符
- 确保字符串以
\0结尾,防止越界访问。
(3)不会忽略空格
- 与
scanf("%s", str)不同,fgets会读取空格和制表符。
(4)比 gets 更安全
gets已被弃用(C11标准移除),因为它不检查缓冲区大小,容易导致溢出。
3. 使用示例
示例1:从标准输入(键盘)读取一行
#include <stdio.h>
// 从标准输入(键盘)读取一行
int main()
{
char buffer[100];
printf("please input data:\n");
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
printf("the input is: %s\n", buffer);
}
else {
printf("fgets read fail\n");
}
return 0;
}
运行结果:
please input data:
nimehao
the input is: nimehao
示例2:从文件读取
#include <stdio.h>
#include <string.h> // used for strcmp
// 利用fgets从文件读取数据
int main()
{
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
perror("fopen error");
return 1;
}
char line[100];
printf("size of line is :%zu\n", sizeof(line));
while (fgets(line, sizeof(line), fp) != NULL)
{
// two compare method
// if (strcmp(line, "\n") == 0)
if (line[0] == '\n')
{
printf("empty line\n");
continue;
}
printf("line:%s", line);
}
fclose(fp);
return 0;
}
data.txt
hello, c nihao
I get you.
output:
size of line is :100
line:hello, c nihao
empty line
line:I get you.
4. 关键注意事项
(1) 换行符 \n 的处理
fgets会保留换行符(如果一行完整读取)。- 检查是否读取了换行符:
if (buffer[strlen(buffer) - 1] == '\n') {
buffer[strlen(buffer) - 1] = '\0'; // 去掉换行符
}
(2) 缓冲区大小 n 的选择
- 必须预留1字节给
\0:
-
- 如果
char buf[100],则n应设为100(最多读99字符 +\0)。
- 如果
- 缓冲区不足时:
-
- 如果一行超过
n-1字符,剩余部分会在下一次fgets调用时读取。
- 如果一行超过
(3) 与 scanf 的区别
|
特性 |
|
|
|
读取方式 |
按行读取(含空格) |
按格式读取(遇空格停止) |
|
安全性 |
安全(指定缓冲区大小) |
可能溢出(如 |
|
换行符 |
保留 |
不保留 |
推荐:优先使用 fgets + sscanf 组合,避免 scanf 的安全问题。
fgets 负责安全地读取一行输入(避免 gets 或 scanf 直接读导致的溢出)。
scanf 从 fgets 读取的字符串中提取结构化数据(如整数、浮点数、字符串等)
具体为:
- 用
fgets读取一行到缓冲区。 - 用
sscanf从缓冲区中提取数据。 - 检查
sscanf的返回值,确保解析成功。
示例如下:
#include <stdio.h>
// fgets + sscanf 组合使用
// fgets 负责安全地读取一行输入(避免 gets 或 scanf 直接读导致的溢出)。
// sscanf 从 fgets 读取的字符串中提取结构化数据(如整数、浮点数、字符串等)
int main()
{
char buffer[100];
int num1, num2;
printf("please input two integer(eg:10 20):\n");
if (fgets(buffer, sizeof(buffer), stdin) == NULL)
{
printf("fgets read error\n");
return 1;
}
if (sscanf(buffer, "%d %d", &num1, &num2) != 2)
{
printf("input format error\n");
return 1;
}
printf("the input data is %d and %d\n", num1, num2);
return 0;
}
output:
please input two integer(eg:10 20):
12 334
the input data is 12 and 334
5. 常见问题
Q1: fgets 为什么会读到空行?
- 原因:文件中有空行(仅
\n),fgets会读取为"\n\0"。 - 解决方法:
if (buffer[0] == '\n') {
// 处理空行
}
Q2: fgets 能否读取二进制文件?
- 不推荐:
fgets是文本行读取函数,遇到\0会停止。 - 二进制文件应使用
fread:
fread(buffer, 1, size, file); // 按字节读取
6. 总结
|
特性 |
说明 |
|
用途 |
安全读取文本行(文件或标准输入)。 |
|
换行符处理 |
保留 |
|
缓冲区安全 |
必须指定最大长度( |
|
替代 |
是更安全的替代方案。 |
|
二进制文件 |
不适用,应使用 |
最佳实践:
- 始终检查
fgets的返回值(是否为NULL)。 - 处理换行符(
\n)以避免后续问题。 - 优先使用
fgets+sscanf替代scanf。
2229

被折叠的 条评论
为什么被折叠?



