通过Makefile运行C程序时realloc失败,手动运行正常的问题
问题:Makefile运行C程序时realloc超过40字节失败,手动运行正常
已编译完成的C程序main.exe(通过gcc main.c -o main.exe编译),手动运行./main.exe时一切正常,但通过Makefile的make run命令运行时,有50%概率出现异常——当realloc申请的内存大小超过40字节后持续失败。
程序代码
#include <string.h> #include <stdio.h> #include <stdlib.h> typedef struct { char **array; int size; } stringList; void add_string(stringList *list, char *string) { printf("Arr size: %zu. ", ((list->size) + 1) * sizeof(char *)); char **newAddress = realloc(list->array, ((list->size) + 1) * sizeof(char *)); if (newAddress != NULL) { char *newString = malloc((strlen(string) + 1) * sizeof(char)); if (newString != NULL) { strcpy(newString, string); list->array = newAddress; list->array[list->size] = newString; list->size++; printf("Fine. "); } else { printf("Allocating new string failed. "); } } else { printf("Allocating new array failed. "); } } int main(int argc, char *argv[]) { stringList list = { NULL, 0 }; if (argc != 3) { argv[1] = malloc(3 * sizeof(char)); argv[1] = "in"; argv[2] = malloc(3 * sizeof(char)); argv[2] = "out"; } FILE *input = fopen(argv[1], "r"); FILE *output = fopen(argv[2], "w"); // I found that the line above may cause the problem (but I left it because I will use it) char buffer[256] = {0}; while (fscanf(input, "%s", buffer) != EOF) { add_string(&list, buffer); } fclose(input); fclose(output); return 0; }
测试用in文件内容
1 2 3 4 5 6 7 8 9 10 11 12 13
手动运行输出
PS C:\Users\Ivan\Desktop\maketest> ./main.exe Arr size: 4. Fine. Arr size: 8. Fine. Arr size: 12. Fine. Arr size: 16. Fine. Arr size: 20. Fine. Arr size: 24. Fine. Arr size: 28. Fine. Arr size: 32. Fine. Arr size: 36. Fine. Arr size: 40. Fine. Arr size: 44. Fine. Arr size: 48. Fine. Arr size: 52. Fine. PS C:\Users\Ivan\Desktop\maketest> ./main.exe Arr size: 4. Fine. Arr size: 8. Fine. Arr size: 12. Fine. Arr size: 16. Fine. Arr size: 20. Fine. Arr size: 24. Fine. Arr size: 28. Fine. Arr size: 32. Fine. Arr size: 36. Fine. Arr size: 40. Fine. Arr size: 44. Fine. Arr size: 48. Fine. Arr size: 52. Fine.
Makefile内容
.PHONY: run run: ./main.exe
问题原因分析
核心问题:非法修改
argv数组
在main函数中,当命令行参数不足3个时,代码先给argv[1]和argv[2]分配内存,紧接着又将它们赋值为字符串常量"in"和"out":argv[1] = malloc(3 * sizeof(char)); argv[1] = "in"; argv[2] = malloc(3 * sizeof(char)); argv[2] = "out";这会导致两个严重问题:
- 内存泄漏:
malloc分配的内存地址被覆盖,永远无法释放; - 未定义行为:
argv是由操作系统维护的进程参数数组,直接修改其元素指向会破坏进程的内存布局。这种行为的后果是不确定的,在不同运行环境(手动运行vs Makefile运行)下会触发不同的内存异常,表现为后续realloc申请内存失败。
- 内存泄漏:
次要问题:文件操作未做错误检查
fopen可能因为权限、文件不存在等原因失败,直接使用返回的空指针会进一步加剧内存异常的概率。
解决方案
1. 避免修改argv,改用局部变量存储默认文件名
修改main函数开头部分,用局部变量管理默认文件名,仅在参数合法时替换:
int main(int argc, char *argv[]) { stringList list = { NULL, 0 }; const char *input_file = "in"; const char *output_file = "out"; // 仅当参数数量正确时,使用命令行传入的文件名 if (argc == 3) { input_file = argv[1]; output_file = argv[2]; } FILE *input = fopen(input_file, "r"); FILE *output = fopen(output_file, "w"); // ... 后续代码不变 }
2. 添加文件打开失败的检查
避免使用空指针导致的未定义行为:
if (!input) { perror("Failed to open input file"); return 1; } if (!output) { perror("Failed to open output file"); fclose(input); return 1; }
3. 释放已分配的内存,避免泄漏
在程序结束前,释放stringList中存储的所有字符串和数组本身:
// 在fclose之后、return之前添加 for (int i = 0; i < list.size; i++) { free(list.array[i]); } free(list.array);
内容的提问来源于stack exchange,提问作者iab
相关产品推荐
相关产品推荐

