You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过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";
    

    这会导致两个严重问题:

    1. 内存泄漏:malloc分配的内存地址被覆盖,永远无法释放;
    2. 未定义行为: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:19:52