【问题标题】:Using free on the data that I malloc'd is not working对我 malloc'd 不起作用的数据使用 free
【发布时间】:2021-12-29 20:25:39
【问题描述】:

在我的程序开始时,我创建了这个结构:

struct directive {
    char gate[17];
    int n;
    int s;
    int *inputs;
    int *outputs;
    int *selectors;
};

这里包含了我的全部主要功能:

int main(int argc, char** argv) {
    if (argc - 1 != 1) {
        printf("Invalid number of arguments\n");
        return 0;
    }

    //get file, return if invalid path
    FILE *file = fopen(argv[1], "r");
    if (!file) {
        printf("Invalid input\n");
        return 0;
    }

    //make temp of circuit with struct directive
    int scount = 0;
    struct directive* temp = NULL;
    int size = 2;
    int icount = 0;
    int ocount = 0;
    int tcount = 0;
    char dir[17];
    char **names;
    int *values;

    //get INPUT info
    fscanf(file, " %s", dir);
    fscanf(file, "%d", &icount);

    size += icount;
    names = malloc(size * sizeof(char *));
    names[0] = malloc(2 * sizeof(char));     //MALLOC
    strcpy(names[0], "0");
    names[1] = malloc(2 * sizeof(char));     //MALLOC
    strcpy(names[1], "1");

    int i;
    for (i = 0; i < icount; i++) {
        names[i + 2] = malloc(17 * sizeof(char));
        fscanf(file, "%*[: ]%16s", names[i + 2]);
    }

    //get OUTPUT info
    fscanf(file, " %s", dir);
    fscanf(file, "%d", &ocount);
    size += ocount;
    names = realloc(names, size * sizeof(char *));
    for (i = 0; i < ocount; i++) {
        names[i + icount + 2] = malloc(17 * sizeof(char));
        fscanf(file, "%*[: ]%16s", names[i + icount + 2]);
    }

    //get temp
    struct directive step;
    while (!feof(file)) {
        int numInputs = 2, numOutputs = 1;

        int sc = fscanf(file, " %s", dir);
        if (sc != 1) {
            break;
        }
        scount++;
        step.n = 0;
        step.s = 0;
        strcpy(step.gate, dir);

        if (strcmp(dir, "NOT") == 0) {
            numInputs = 1;
        }
        if (strcmp(dir, "PASS") == 0) {
            numInputs = 1;
        }
        if (strcmp(dir, "DECODER") == 0) {
            fscanf(file, "%d", &numInputs);
            step.n = numInputs;
            numOutputs = pow(2, numInputs);
        }
        if (strcmp(dir, "MULTIPLEXER") == 0) {
            fscanf(file, "%d", &numInputs);
            step.s = numInputs;
            numInputs = pow(2, numInputs);
        }

        step.inputs = malloc(numInputs * sizeof(int));
        step.outputs = malloc(numOutputs * sizeof(int));
        step.selectors = malloc(step.s * sizeof(int));

        char v[17];
        for (i = 0; i < numInputs; i++) {
            fscanf(file, "%*[: ]%16s", v);
            step.inputs[i] = indexOf(size, names, v);
        }

        for (i = 0; i < step.s; i++) {
            fscanf(file, "%*[: ]%16s", v);
            step.selectors[i] = indexOf(size, names, v);
        }

        for (i = 0; i < numOutputs; i++) {
            fscanf(file, "%*[: ]%16s", v);
            int idx = indexOf(size, names, v);
            if (idx == -1) {
                size++;
                tcount++;
                names = realloc(names, size * sizeof(char *));
                names[size - 1] = malloc(17 * sizeof(char));
                strcpy(names[size - 1], v);
                step.outputs[i] = size - 1;
            }
            else {
                step.outputs[i] = idx;
            }
        }

        //add step to list of temp
        if (!temp) {
            temp = malloc(sizeof(struct directive));
        } else {
            temp = realloc(temp, scount * sizeof(struct directive));
        }
        temp[scount - 1] = step;


    }

    // initialize values array
    values = malloc(size * sizeof(int));
    resetValues(size, values);

    while(1 < 2) {
        //print inputs
        for (i = 0; i < icount; i++) {
            printf("%d ", values[i + 2]);
        }
        printf("|");

        //run through temp, calculate outputs
        for (i = 0; i < scount; i++) {
            struct directive step = temp[i];
            if (strcmp(step.gate, "NOT") == 0) {
                NOT(values, step.inputs[0], step.outputs[0]);
            }
            if (strcmp(step.gate, "AND") == 0) {
                AND(values, step.inputs[0], step.inputs[1], step.outputs[0]);
            }
            if (strcmp(step.gate, "OR") == 0) {
                OR(values, step.inputs[0], step.inputs[1], step.outputs[0]);
            }
            if (strcmp(step.gate, "NAND") == 0) {
                NAND(values, step.inputs[0], step.inputs[1], step.outputs[0]);
            }
            if (strcmp(step.gate, "NOR") == 0) {
                NOR(values, step.inputs[0], step.inputs[1], step.outputs[0]);
            }
            if (strcmp(step.gate, "XOR") == 0) {
                XOR(values, step.inputs[0], step.inputs[1], step.outputs[0]);
            }
            if (strcmp(step.gate, "PASS") == 0) {
                PASS(values, step.inputs[0], step.outputs[0]);
            }
            if (strcmp(step.gate, "DECODER") == 0) {
                DECODER(values, step.n, step.inputs, step.outputs);
            }
            if (strcmp(step.gate, "MULTIPLEXER") == 0) {
                MUX(values, step.s, step.inputs, step.selectors, step.outputs[0]);
            }

        }

        //print outputs
        for (i = 0; i < ocount; i++) {
            printf(" %d", values[icount + i + 2]);
        }
        printf("\n");

        if (!incrementInputs(values, icount)) {
            break;
        }

    }


    for (i = 0; i < icount; i++) {
        free(names[i + 2]);
    }

    for (i = 0; i < ocount; i++) {
        free(names[i + icount + 2]);
    }

    free(step.inputs);
    free(step.outputs);
    free(step.selectors);

    free(names[0]);
    free(names[1]);

    free(values);
    free(temp);

    return 0;
}

我遇到的问题是在编译时,我的地址清理程序告诉我,我在第 203 和 204 行有内存泄漏,这些是以下 malloc:

    names = realloc(names, size * sizeof(char *));
    names[size - 1] = malloc(17 * sizeof(char));

您可以看到我释放了分配给它的三行,那么它实际上没有释放的原因是什么?由于我在 main 之后做了其他事情,我是否必须循环访问某些内容并使用 free?

【问题讨论】:

    标签: c memory-management memory-leaks malloc


    【解决方案1】:

    您在循环中分配内存,但只释放您在上次迭代中获得的内存:

       ...
       while (!feof(file)) {
           ...
           step.inputs = malloc(numInputs * sizeof(int));
           step.outputs = malloc(numOutputs * sizeof(int));
           step.selectors = malloc(step.s * sizeof(int));
           ...
       }
       ...
       free(step.inputs);
       free(step.outputs);
       free(step.selectors);
       ...
    

    【讨论】:

    • 刚刚得到它。非常感谢
    • 您已经接受了 Oka 的回答。另一种选择是跟踪每个的总大小并使用realloc()。这样您就可以调整每个分配的大小,而不是为每个循环迭代创建一个新的。
    • 它确实有效,但现在进一步查看后,我意识到它也在以下位置泄漏:names = realloc(names, size * sizeof(char *));名称[大小 - 1] = malloc(17 * sizeof(char));
    • 是的,我只看了你问的问题。
    • 如果您的原始问题已得到解答,请接受并继续。如果您需要其他方面的帮助,请打开一个新问题。见minimal reproducible example
    【解决方案2】:

    由于while (!feof(file)) { ... } 循环的最终迭代,这组调用仅释放step 的最后保留值。

    free(step.inputs);
    free(step.outputs);
    free(step.selectors);
    

    每次迭代,step 都会被复制到 temp 的一个元素中,因此您必须在释放 temp 之前释放每个元素的成员。

    for (int i = 0; i < scount; i++) {
        free(temp[i].inputs);
        free(temp[i].outputs);
        free(temp[i].selectors);
    }
    

    【讨论】:

    • 刚刚得到它。谢谢!
    • 我进一步更新了问题
    【解决方案3】:

    其他人已经指出了主要问题,所以我不会重复它们,但我想提供一些提示以使分配更安全。

    当你malloc() 并且需要提供数据大小时,使用sizeof(type) 并没有错,但是如果你输入错误,就像一个简单的错字一样,你会得到错误的内存量。即使您没有犯任何错误,但如果您稍后更改指针类型,它也会对您不利。编译器不会检查您给 malloc() 的大小是否正确(它确实不能),因此您不会收到任何关于您为错误类型分配大小的位置的警告。

    因此,在诸如

    之类的分配中
        names = malloc(size * sizeof(char *));
        names[0] = malloc(2 * sizeof(char));
        names[i + 2] = malloc(17 * sizeof(char));
        step.inputs = malloc(numInputs * sizeof(int));
        step.outputs = malloc(numOutputs * sizeof(int));
        step.selectors = malloc(step.s * sizeof(int));
    

    所有sizeof() 都是错误的潜在藏身之处。

    相反,您可以从分配分配的指针获取大小。当然,并非总是如此,有时您需要分配一些东西并且您没有分配给的变量——将分配的内存发送给一个函数或类似的东西,但 99% 的时间,如果你 malloc 你正在分配给一个变量。您还可以使用sizeof 获取变量指向的类型的大小。 sizeof 运算符有两种风格。一个接受类型,sizeof(type),一个接受表达式,sizeof expressionssizeof(expression);括号在这里是可选的。

    您可以将上面的分配更改为:

        names = malloc(size * sizeof *names);
        names[0] = malloc(2 * sizeof *names[0])
        names[i + 2] = malloc(17 * sizeof *names[i + 2])
        step.inputs = malloc(numInputs * sizeof *step.inputs);
        step.outputs = malloc(numOutputs * sizeof *step.outputs);
        step.selectors = malloc(step.s * sizeof *step.selectors);
    

    你需要在这里取消引用变量,否则你会得到指针的大小而不是它指向的内容,但是不要担心这个取消引用。编译器不会发出实际取消引用的代码,考虑到指针尚未初始化,这在任何情况下都是灾难性的。不,指针只是计算出表达式的类型并从那里获取大小。这样,您要为其分配空间的分配和类型保持一致。

    另一件事是你做的realloc()

        names = realloc(names, size * sizeof(char *));
    

    诚然,它不太可能失败,但如果失败了,realloc() 返回 NULL,如果失败了,它还没有释放其输入指针。如果这个realloc() 失败了,你会在names 中有NULL,你就会泄露names 之前指向的内存。

    出于这个原因,您通常不应将来自realloc() 的结果直接分配给输入指针。最好分配给一个临时变量,检查是否分配失败,如果没有分配给你想要保存结果的变量。

        char **tmp = realloc(names, size * sizeof *tmp);
        if (!tmp) abort(); // handle alloc failure
        names = tmp;
    

    当然,这取决于您是否计划处理分配失败。我在这里只是abort(),您可以在不分配tmp 变量的情况下做同样的事情

        names = realloc(names, size * sizeof *tmp);
        if (!names) abort(); // handle alloc failure
    

    如果您在桌面上运行,分配错误不太可能成为问题,并且使用一些适当的错误消息终止程序是一个简单的修复,可能没问题。

    【讨论】:

    • 谢谢你,这是一个巨大的帮助。关于免费电话,你有什么可以告诉我的吗?尤其是 realloc 线路?
    • realloc() 将在必要时自动释放输入指针(因此,在分配给 tmp 之后,如果您想避免麻烦,您必须将 tmp 分配回名称)。最后,您必须像其他分配的内存一样释放名称。
    • 我不确定在哪里放置 free(names[size-1]);那么
    • 无论你在哪里免费names;与realloc()无关;您只需要释放指针,就好像您从未调用过realloc()
    • 嗯,我的 frees 中有这条线,但它仍然坚持 names[size - 1] 正在泄漏。这可能是其他原因的结果
    猜你喜欢
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-30
    • 2021-03-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多