ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

C 语言文件 IO 学习Day03:从基础函数到实战踩坑(BMP 读取 + 词典查询)

C 语言文件 IO 学习Day03:从基础函数到实战踩坑(BMP 读取 + 词典查询) 本文为 C 语言软件编程学习 Day03 笔记系统梳理标准 IO 库函数、核心易混点对比并结合「BMP 图片宽高读取」「英汉词典查询」两个实战项目总结实操中高频踩坑点文章目录前言一、文件 IO 核心函数全解1. fgetc读取单个字符2. fputs写入字符串3. fgets读取一行字符串4. fprintf格式化写入文件5. fwrite整块数据写入6. fread整块数据读取7. fseek设置文件偏移位置8. ftell获取当前偏移量9. rewind回到文件开头二、易混函数深度对比1. gets 与 fgets 核心区别2. puts 与 fputs 核心区别三、实战项目与踩坑复盘项目 1读取 24 位 BMP 图片的宽度和高度项目 2英汉词典查询系统四、高频易错点速查表五、课后练习文件拷贝前言第三天的学习核心围绕标准文件 IO 操作展开从单字符读写到整块数据读写再到文件位置偏移控制最终落地到两个实战场景。这部分知识点函数多、细节碎坑点密集尤其字符串与指针结合的地方非常容易出错。本文按「函数大全 → 易混对比 → 实战项目 → 易错汇总」的结构整理方便复习和避坑。一、文件 IO 核心函数全解1. fgetc读取单个字符int fgetc(FILE *stream);功能从文件流中读取一个字符返回值成功返回字符的 ASCII 码值失败或读到文件末尾返回EOF注意返回值用int接收而不是char因为EOF是超出 char 范围的负值2. fputs写入字符串int fputs(const char *s, FILE *stream);功能将字符串写入指定文件流返回值成功返回非负整数失败返回EOF特点不会自动追加换行符\n原样输出字符串内容3. fgets读取一行字符串char *fgets(char *s, int size, FILE *stream);功能从流中读取一行字符串最多读取size-1个字符末尾自动补\0返回值成功返回缓冲区首地址失败或读到文件末尾返回NULL核心特点自带长度保护不会缓冲区溢出会保留行尾的换行符\n不会自动丢弃既可读取标准输入stdin也可读取普通文件4. fprintf格式化写入文件int fprintf(FILE *stream, const char *format, ...);功能按格式化字符串将数据写入指定文件流返回值成功返回实际写入的字符个数失败返回负数对比printf等价于fprintf(stdin, ...)只是默认输出到终端5. fwrite整块数据写入size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);功能向文件写入nmemb个对象每个对象占size字节参数ptr待写入数据的内存首地址size单个对象的字节大小nmemb要写入的对象数量返回值成功返回实际写入的完整对象个数失败返回 06. fread整块数据读取size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);功能从文件中读取nmemb个对象每个对象占size字节存入 ptr 指向的内存返回值成功返回实际读到的完整对象个数失败或读到文件末尾返回 0两种常用写法读单个结构体 / 整数fread(var, sizeof(var), 1, fp)→ 返回值判断是否等于 1读字节缓冲区fread(buf, 1, sizeof(buf), fp)→ 返回值就是读到的字节数7. fseek设置文件偏移位置int fseek(FILE *stream, long offset, int whence);功能重新定位文件读写光标的位置基准参数 whenceSEEK_SET从文件开头计算偏移SEEK_CUR从当前光标位置计算偏移SEEK_END从文件末尾计算偏移返回值成功返回 0失败返回 - 18. ftell获取当前偏移量long ftell(FILE *stream);功能获取当前光标距离文件开头的字节偏移量经典用法配合 fseek 获取文件总大小fseek(fp, 0, SEEK_END); long file_size ftell(fp);9. rewind回到文件开头void rewind(FILE *stream);功能将文件光标直接重置到文件开头等价于fseek(fp, 0, SEEK_SET);二、易混函数深度对比1. gets 与 fgets 核心区别这是考试最高频考点也是实操最容易踩坑的点。表格对比维度gets()fgets()缓冲区长度无长度检查输入多长写多长强制指定 size最多读 size-1 个字符溢出风险极高C11 标准已正式删除安全不会越界换行符处理读到换行直接丢弃替换为\0换行符保留在字符串中再补\0读取来源只能从标准输入读取可从任意文件流读取推荐程度禁止使用标准推荐写法踩坑提醒用fgets从键盘读取单词后直接和文件内单词做strcmp会永远失败因为字符串末尾多了一个\n。必须先清除换行符str[strcspn(str, \n)] \0;2. puts 与 fputs 核心区别表格对比维度puts()fputs()换行符自动在末尾追加一个\n不会额外添加任何字符原样输出输出目标只能输出到标准输出可输出到任意文件流三、实战项目与踩坑复盘项目 1读取 24 位 BMP 图片的宽度和高度需求从 BMP 文件中读取图片分辨率已知宽度在文件偏移 18 字节处占 4 字节高度在偏移 22 字节处占 4 字节。核心代码#include stdio.h int main(void) { FILE *fp fopen(src.bmp, rb); // 二进制文件必须用rb打开 if (NULL fp) { perror(fopen failed); return -1; } unsigned int width 0, height 0; fseek(fp, 18, SEEK_SET); // 定位到宽度字段 fread(width, 4, 1, fp); fread(height, 4, 1, fp); // 读完宽度光标自动后移4字节正好对准高度 printf(宽度%u\n高度%u\n, width, height); fclose(fp); return 0; }高频踩坑点偏移计算错误误以为宽度从 17 字节开始正确逻辑文件头占 14 字节0-13 biSize 占 4 字节14-17 18宽度从 18 号字节开始。字段占 N 字节下一字段起始位置 起始偏移 N。用文本模式打开二进制文件BMP 是二进制文件必须用rb模式否则数据会错乱。小端序问题BMP 采用小端存储x86/x64CPU 原生小端直接 fread 到 int 变量即可无需手动翻转字节。项目 2英汉词典查询系统需求终端输入单词从词典文件每行格式单词 释义释义内部含空格中匹配并打印对应释义。正确实现strtok 指针遍历#include stdio.h #include string.h int main(void) { FILE *fp fopen(dict.txt, r); if (NULL fp) { perror(fopen failed); return -1; } char str[100] {0}; char tmpbuff[4096] {0}; gets(str); // 仅作业演示使用实际开发禁用gets while (fgets(tmpbuff, sizeof(tmpbuff), fp) ! NULL) { // 第一步strtok只调用一次切出第一个单词 char *word strtok(tmpbuff, ); if (word NULL) continue; // 第二步遍历指针越过单词末尾的\0找到释义区域 char *meaning word; while (*meaning ! \0) meaning; // 走到单词结尾 meaning; // 跨过strtok写入的\0 // 第三步跳过释义开头连续的空格 while (*meaning ! \0 *meaning ) { meaning; } // 第四步字符串比较必须用strcmp if (strcmp(str, word) 0) { printf(含义为%s, meaning); break; } } fclose(fp); return 0; }踩坑大汇总低级错误文件名加双引号fopen(argv[1], r); // ❌ 去找名叫argv[1]的文件永远打开失败 fopen(argv[1], r); // ✅ 正确访问命令行参数致命错误用比较字符串比较的是指针地址不是字符串内容。内容比较必须用strcmp相等返回 0。经典错误多次调用 strtok 切碎释义strtok(NULL, )会把释义内部的空格也当分隔符切开只能拿到半截释义。正确做法是只调用一次 strtok 切单词剩余内容靠指针遍历获取。隐形错误fgets 带换行符输入单词和词典行尾都可能带\n不处理会导致 strcmp 永远匹配失败。四、高频易错点速查表易错点错误写法正确写法字符串比较if(str1 str2)if(strcmp(str1, str2) 0)命令行参数传文件名fopen(argv[1],r)fopen(argv[1],r)二进制文件打开fopen(a.bmp,r)fopen(a.bmp,rb)gets 安全问题gets(str)fgets(str, sizeof(str), stdin)fgets 换行符直接拿去 strcmp先str[strcspn(str,\n)]\0strtok 切释义strtok(NULL, )只切一次单词剩余内容指针遍历BMP 偏移计算宽度偏移 17宽度偏移 18ftell 返回值%d打印%ld打印long 类型指针遍历边界先判断字符再判断 \0先判断!\0再判断字符利用短路保护五、课后练习文件拷贝利用fread和fwrite实现二进制文件拷贝图片、文档均可核心框架#include stdio.h int main(int argc, char *argv[]) { if (argc 3) { printf(usage: ./a.out src_file dst_file\n); return -1; } FILE *fp_src fopen(argv[1], rb); FILE *fp_dst fopen(argv[2], wb); char buf[4096] {0}; size_t n 0; while ((n fread(buf, 1, sizeof(buf), fp_src)) 0) { fwrite(buf, 1, n, fp_dst); } fclose(fp_src); fclose(fp_dst); return 0; }
返回列表