【问题标题】:Struct and memory allocation with loop带循环的结构和内存分配
【发布时间】:2017-05-24 04:22:52
【问题描述】:

我一直试图在最后释放()内存,但是我的导师说我已经创建了 3 个 malloc 指针(使用当前设置)。

注意:我希望尽可能详细地解释 malloc/内存中实际发生的情况。

如果我能提供指导以确保没有内存泄漏,我将不胜感激。

我已经写了以下内容。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #define LUNCH_ITEMS 5
    #define REMAINING 2
    #define CHAR_SIZE 256

    int main(void)
    {
        struct Food
        {
            char *name; //name attribute of food
            int weight, calories;
        } lunch[LUNCH_ITEMS] = {{"apple", 4, 100}, {"salad", 2, 80},};
        int loopCount;
        //INPUT
        char *namePtr = NULL;
        for (loopCount = REMAINING; loopCount < LUNCH_ITEMS; ++loopCount)
        {
            char tempBuffer[CHAR_SIZE];
            printf("Enter name of item,the weight of item, and the calories in that item: \n");
            // store name string in a tempBuffer. weight and calories directly into lunch structure array address
            scanf("%255s %d %d", tempBuffer, &lunch[loopCount].weight, &lunch[loopCount].calories);
            // get the exact size of (memory of) the input string including add one for null char
            size_t exactMemory = strlen(tempBuffer) + 1;
            //dynamically allocate the exact amount of memory determined in the previous step
            namePtr = (char *)malloc(exactMemory * sizeof(char));
            // check if no memory is allocated for foodPtr
    if (namePtr == NULL)
    {
        fprintf(stderr, "Not enough memory available***\n Terminating Program");
        exit(1);
    }
    //store the pointer to it in the name member of the structure in
    //the current lunch array element.
    (lunch + loopCount)->name = namePtr;
    // Copy the food name (stored in tempbuffer) into the dynamically-allocated
    // memory using the memcpy function

            memcpy(namePtr, tempBuffer, exactMemory);
    //(lunch + loopCount)->name = namePtr;
        }
    //DISPLAY
        printf("Item                        Weight       Cals\n---------------------------------------------\n");
        for (loopCount = 0; loopCount < LUNCH_ITEMS; loopCount++)
        {
            int weight = lunch[loopCount].weight;
            int cals = lunch[loopCount].calories;
            printf("%-12.20s%22d%11d\n", (lunch + loopCount)->name, weight, cals);
            if (loopCount > REMAINING)
            {
                //(lunch+loopCount)->name = NULL;
                namePtr = NULL;
                free(namePtr);
                //free((lunch + loopCount)->name);
            }
        }
        //De-allocate all malloc'd memory
        return EXIT_SUCCESS;
    }

我的输出 -

Item Weight Cals
-----------------
apple  4   100
salad  2    80
hello  22   33
maybe  44   45
right 100   200

【问题讨论】:

  • Valgrind 是一个很好的工具,可以检查您的程序是否泄漏内存或对内存进行其他不明智的操作。在您的程序中使用 valgrind 可能会发现几个问题。
  • 既然有人指出,那我就照办吧:do not cast the return value of malloc.
  • 注意:strcpy(甚至strncpy)的意图可能比memcpy更清晰。
  • 至于实际问题:您在循环中运行malloc,这会发生三次。因此,您拥有三个malloc-ed 内存项。您确实释放了它们,尽管我认为您已经落后了:loopcount &gt; REMAINING 将错过第三个午餐项目(索引 [2]),其名称是使用 malloc 动态分配的。
  • 将指针设置为 null 然后freeing 显然不正确

标签: c struct memory-leaks malloc dynamic-memory-allocation


【解决方案1】:

看初始化循环:

for (loopCount = REMAINING; loopCount < LUNCH_ITEMS; ++loopCount)
{
    // The code inside the loop will be executed for
    // loopCount being equal to 
    //     REMAINING
    //     REMAINING + 1
    //     ....
    //     LUNCH_ITEMS - 1
    //
    // So in your case, you execute this code for
    // loopCount equal to 2, 3 and 4
}

换句话说,循环内的代码被执行了3次,即你调用malloc 3次

以同样的方式,查看释放内存的循环。

for (loopCount = 0; loopCount < LUNCH_ITEMS; loopCount++)
{
    // you execute this code for
    // loopCount equal to 0, 1, 2, 3 and 4

    // ....

    if (loopCount > REMAINING)
    {
        // Since REMAINING is 2, you execute this code for
        // loopCount equal 3 and 4
    }
}

所以if 正文中的代码只执行了 2 次。你真的想这样做 3 次(即 for loopCount 等于 2、3 和 4)。所以需要把代码改成:

    if (loopCount >= REMAINING)  // Notice the = sign
    {
        // Since REMAINING is 2, you execute this code for
        // loopCount equal 2, 3 and 4
    }

现在关于mallocfree。当您释放内存时,即使用free您必须准确传递 malloc 返回给您的值

在初始化时,你保存了这样的指针:

namePtr = (char *)malloc(exactMemory * sizeof(char));
// ...
(lunch + loopCount)->name = namePtr;  // Save pointer

所以(lunch + loopCount)-&gt;name 应该用于free。喜欢:

    if (loopCount >= REMAINING)  // Notice the = sign
    {
        free((lunch + loopCount)->name);

        // Optional part but always after calling free
        (lunch + loopCount)->name = NULL;
    }

顺便说一句:请注意

(lunch + loopCount)->name

相同
lunch[loopCount].name

许多人认为它更容易阅读。

【讨论】:

  • 感谢您的详细解释。我的导师让我看起来好像用 malloc 初始化了 3 个单独的指针(而不是使用 malloc 创建的)。然后我变得非常困惑,把所有东西都撕成碎片,然后重新开始了几次。非常感谢您对 malloc 和 free 如何使用事物的详细解释。在将指针设置为结构成员后,我不理解 malloc 的行为方式。还要感谢关于如何正确使用 NULL 的非常有用的方法,我研究了很多,并且必须对 SO 有误解的语法。
  • 您的解释也真正阐明了我如何看待 free() 函数。确实帮助我以非常直接的方式理解了我正在编写的代码。
【解决方案2】:

我认为您的讲师对 3 个 malloc'ed 字符串的评论是一个非常有力的线索。我注意到您有一个包含 5 个项目的数组,其中预先填充了 2 个项目。 5 - 2 是 3。

另外,请注意 C 中的索引从 0 开始。您预初始化数组的 2 个项目将具有索引 0 和索引 1。索引 2 将是第一个输入的数据。使用 > 2 比较该索引实际上会导致您跳过第一条用户提供的数据的索引。

【讨论】:

  • 当我当前运行程序时,它完成并且所有答案都正确,但该课程的电子邮件提交更正器说我有动态内存错误。当我将 if 块中的 DISPLAY 注释下的代码更改为 >= REMAINING 时,会出现一条错误消息,说明我试图解除分配的点尚未分配。错误不是在显示区域而是在我将 loopCount 设置为“2”的第一个块中吗?
猜你喜欢
  • 2013-05-06
  • 1970-01-01
  • 1970-01-01
  • 2017-07-26
  • 2017-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多