如何解决C程序处理已打开文件时触发的malloc错误?
完善文件复制程序:给输出文件添加
bsh_前缀并逐行读写 我看你已经搭好了程序的基本框架,不过代码还没写完,而且缺少关键的错误检查环节——这在C程序里很容易导致崩溃或者奇怪的行为。下面是补全并优化后的完整代码,我会一步步拆解关键点:
完整代码
#include <stdlib.h> #include <stdio.h> #include <string.h> #define CAT_PREFIX_LEN 4 #define CAT_PREFIX "bsh_" int main(int argc, char** argv) { FILE *toread, *towrite; char *line = NULL; size_t len = 0; ssize_t read; // 1. 检查命令行参数是否合规 if (argc != 2) { fprintf(stderr, "用法: %s <待读取文件名>\n", argv[0]); return EXIT_FAILURE; } // 2. 拼接带前缀的输出文件名 char catfile[CAT_PREFIX_LEN + strlen(argv[1]) + 1]; strcpy(catfile, CAT_PREFIX); strcat(catfile, argv[1]); // 3. 打开输入文件并检查是否成功 toread = fopen(argv[1], "r"); if (toread == NULL) { perror("打开输入文件失败"); return EXIT_FAILURE; } // 4. 打开输出文件并检查是否成功 towrite = fopen(catfile, "w"); if (towrite == NULL) { perror("打开输出文件失败"); fclose(toread); // 即使写入文件打开失败,也要先关闭已打开的输入文件 return EXIT_FAILURE; } // 5. 逐行读取并写入内容 while ((read = getline(&line, &len, toread)) != -1) { if (fputs(line, towrite) == EOF) { perror("写入文件失败"); break; } } // 6. 清理资源,避免泄漏 free(line); fclose(toread); fclose(towrite); return EXIT_SUCCESS; }
关键细节说明
- 参数校验:先判断
argc是否为2,确保用户传入了待处理的文件名,否则打印用法提示并退出——这能避免因argv[1]不存在导致的直接崩溃。 - 文件名拼接:用
strcpy把前缀bsh_复制到数组,再用strcat拼接原文件名,数组长度的计算是精准的(前缀长度+原文件名长度+1,多出来的1是字符串终止符\0的位置),不会出现缓冲区溢出。 - 错误处理:每次调用
fopen后都检查返回值,用perror打印具体错误信息;如果写入文件打开失败,要先关闭已打开的输入文件,避免资源泄漏。 - 逐行读写:用
getline读取行非常省心,它会自动分配足够的内存存储每行内容(所以初始line设为NULL、len设为0即可),读取到的内容包含换行符,用fputs直接写入就能保持原文件格式。 - 资源回收:最后一定要释放
getline分配的内存,关闭两个文件,确保系统资源被正确回收。
可选优化建议
如果担心原文件名过长导致栈上数组catfile溢出,可以改用动态内存分配来存储输出文件名,示例如下:
char *catfile = malloc(CAT_PREFIX_LEN + strlen(argv[1]) + 1); if (catfile == NULL) { perror("内存分配失败"); return EXIT_FAILURE; } // 后续使用完后记得调用 free(catfile);
内容的提问来源于stack exchange,提问作者Christopher Berry
相关产品推荐
相关产品推荐

