【问题标题】:realloc fails in visual studio, but work using gcc (ntdll.dll)realloc 在 Visual Studio 中失败,但使用 gcc (ntdll.dll)
【发布时间】:2018-08-31 06:06:00
【问题描述】:

我正在使用 Visual Studio 2017,并且我在 C 中有此代码。当我在 VS 中运行时它失败了,但是当我使用 gcc 编译时它运行完美。错误是这样的:

GestaoFinanceira.exe 中的 0x779BE643 (ntdll.dll) 引发异常:0xC0000005:访问冲突读取位置 0x00000009。

这是我的代码。

我正在使用这种结构类型:

struct budget {
    struct tm time;
    float valor;
};

struct geral {
    struct budget *b;
    int nelem_budget;
};

在 main 中,我调用了一个函数,该函数将从文件中读取并保存值是结构 g->b[] 作为 g->nelem_budget 中的元素数

int main() {
    struct geral *g = (struct geral *)malloc(sizeof(struct geral));

    readFileBudget(g);
    // just to check if the read was ok
    showBudget(g->b, g->nelem_budget);

    addBudget(g);
    // to check again if the item added is ok
    showBudget(g->b, g->nelem_budget);

    system("Pause");
    return 0;
}

这是出现错误的时间:

void addBudget(struct geral *g) {
    int month, year;
    float value;

    // in the future, this values are to be an user input
    month = 5;
    year = 2015;
    value = 5000;

    printf("Month: %d, Year: %d, Value: %f\n", month, year, value);

    g->b[g->nelem_budget].time.tm_mon = month;
    g->b[g->nelem_budget].time.tm_year = year;
    g->b[g->nelem_budget].valor = value;

    g->nelem_budget++;

    struct budget *tmp = NULL;
    tmp = g->b;
    g->b = realloc(g->b, g->nelem_budget * sizeof(struct budget));
    if (g->b == NULL) {          //reallocated pointer ptr1
        free(tmp);
        printf("error-addBudget->realloc");
        exit(EXIT_FAILURE);
    }

    // just for debug
    printf("month: %d, year: %d, value: %f\n", g->b[g->nelem_budget - 1].time.tm_mon, g->b[g->nelem_budget - 1].time.tm_year, g->b[g->nelem_budget - 1].valor);
}

我在g->b 数组的末尾有一个空值,这就是为什么我先添加这些值,然后调用realloc

【问题讨论】:

  • g->nelem_budget的值是多少?
  • 请添加函数readFileBudget的代码
  • realloc() 为时已晚。需要在 g->b[g->nelem_budget].time.tm_mon = month;realloc(g->b, g->nelem_budget * sizeof(struct budget)); 之前是 1 个元素太小。
  • 第一个问题的尝试非常好。做得好!您需要显示geral 的实际内容在哪里初始化。
  • edit您的问题并显示minimal reproducible example,包括输入文件

标签: c visual-studio gcc malloc realloc


【解决方案1】:

你需要先重新分配,然后添加一个新元素,而不是反过来。

我不喜欢这个

struct budget *tmp = NULL;
    tmp = g->b;
    g->b = realloc(g->b, g->nelem_budget * sizeof(struct budget));
    if (g->b == NULL) {          //reallocated pointer ptr1
        free(tmp);
        printf("error-addBudget->realloc");
        exit(EXIT_FAILURE);
    }

有几个原因:

realloc 应该这样调用:

struct budget *tmp;

tmp = realloc(g->b, (g->nelem_budget + 1) * sizeof *tmp);

if(tmp == NULL)
{
    // error handling
    return 0; // return error code
}

g->b = tmp;
g->nelem_budget++;

不要在main 以外的函数中使用exit。而不是关闭程序, 使addBudget 成功返回 1,失败返回 0。 addBudget的来电者 应该决定在失败的情况下做什么,而不是addBudget。例如,如果你 把这些函数放在一个库中,你的程序会在出错时自动结束, 这有时是您不希望发生的事情。

所以,函数应该是这样的:

int addBudget(struct geral *g) {
    if(g == NULL)
        return 0;

    int month, year;
    float value;

    // in the future, this values are to be an user input
    month = 5;
    year = 2015;
    value = 5000;

    // reallocate first

    struct budget *tmp = NULL;
    tmp = realloc(g->b, (g->nelem_budget + 1) * sizeof *tmp);

    if(tmp == NULL)
    {
        fprintf(stderr, "error-addBudget->realloc\n");
        return 0;
    }

    g->b = tmp;

    // add new budget after reallocation
    printf("Month: %d, Year: %d, Value: %f\n", month, year, value);

    g->b[g->nelem_budget].time.tm_mon = month;
    g->b[g->nelem_budget].time.tm_year = year;
    g->b[g->nelem_budget].valor = value;

    g->nelem_budget++;

    // just for debug
    printf("month: %d, year: %d, value: %f\n", g->b[g->nelem_budget - 1].time.tm_mon, g->b[g->nelem_budget - 1].time.tm_year, g->b[g->nelem_budget - 1].valor);

    return 1;
}

然后在main:

int main() {
    // using calloc to initialize
    // everything with 0
    struct geral *g = calloc(1, sizeof *g);

    if(g == NULL)
    {
        fprintf(stderr, "Not engough memory\n");
        return 1;
    }

    // you should also check of readFileBudget
    // fails
    readFileBudget(g);

    // just to check if the read was ok
    showBudget(g->b, g->nelem_budget);

    if(addBudget(g) == 0)
    {
        free(g->b);
        free(g);
        return 1;
    }

    // to check again if the item added is ok
    showBudget(g->b, g->nelem_budget);


    // don't forget to free the memory
    free(g->b);
    free(g);

    system("Pause");
    return 0;
}

另见:do not cast malloc

错误信息应该打印到stderr,而不是stdout

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多