0

I have been trying to free() the memory at the end however my instructor stated that I have created 3 malloc'd pointers (with the current settings).

NOTE: I would like as detailed explanation possible regarding the malloc/what's actually going on in memory.

I would appreciate guidance on what I can do to make sure there is no memory leak.

I have written the following.

    #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;
    }

My output -

Item Weight Cals
-----------------
apple  4   100
salad  2    80
hello  22   33
maybe  44   45
right 100   200
Community
  • 1
  • 1
Donner
  • 13
  • 4
  • Valgrind is a good tool for checking whether your program leaks memory or does other unwise things with memory. Using valgrind on your program may reveal several issues. –  May 24 '17 at 04:29
  • Since someone else will point it out, I'll do it: [do not cast the return value of malloc](https://stackoverflow.com/questions/1565496/specifically-whats-dangerous-about-casting-the-result-of-malloc). –  May 24 '17 at 04:30
  • Note: `strcpy` (or even `strncpy`) may be clearer in your intent than `memcpy`. –  May 24 '17 at 04:33
  • As for the actual question: you run `malloc` in the loop, which happens three times. Thus, you have three `malloc`-ed memory items. You do free them, though I think you're off by one: `loopcount > REMAINING` will miss the third lunch item (index `[2]`), whose name was dynamically assigned with malloc. –  May 24 '17 at 04:35
  • 1
    Setting a pointer to null and then `free`ing it is clearly not correct – M.M May 24 '17 at 04:41
  • @Evert Thank you for the responses! unfortunately memcpy is the mandatory function given in the instructions. – Donner May 24 '17 at 04:54
  • @Evert When I run the program currently it finishes and has all the answers correct but the email submission corrector for the class says I have the dynamic memory errors. when I do change the code under the DISPLAY comment in the if block to >= REMAINING there is an error message about the point I am trying to deallocate has not been allocated – Donner May 24 '17 at 04:58
  • See MM's comment about that error. –  May 24 '17 at 05:01
  • Great! Got rid of the setting to null. Might I ask, what is Valgrind? – Donner May 24 '17 at 05:42

2 Answers2

0

I think your instructor's comment about 3 malloc'ed strings is a pretty strong clue. I notice you have an array of 5 items, with 2 items pre-populated. 5 - 2 is 3.

Also, please be aware that indexes in C start from 0. The 2 items you pre-initialize your array with will have index 0 and index 1. Index 2 will be the first entered data. Comparing that index using > 2 will actually cause you to skip over the index of the first piece of user supplied data.

aghast
  • 14,785
  • 3
  • 24
  • 56
  • When I run the program currently it finishes and has all the answers correct but the email submission corrector for the class says I have the dynamic memory errors. when I do change the code under the DISPLAY comment in the if block to >= REMAINING there is an error message about the point I am trying to deallocate has not been allocated. Is the error not in the Display area but in my first block with setting loopCount to '2'? – Donner May 24 '17 at 05:01
0

Look at the initialization loop:

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
}

In other words, the code inside the loop is executed 3 times, i,e, you call malloc 3 times.

In the same way, look at the loop where you release the memory.

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
    }
}

So the code in the body of the if is only executed 2 times. You really want to do it 3 times (i.e. for loopCount equal 2, 3 and 4). So you need to change the code to:

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

Now regarding malloc and free. When you release memory, i.e. using free, you must pass exactly the value returned to you by malloc

In the initialization you saved the pointer like this:

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

So it is (lunch + loopCount)->name that shall be used for free. Like:

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

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

BTW: Notice that

(lunch + loopCount)->name

is the same as

lunch[loopCount].name

which many consider easier to read.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • Thank you for your detailed explanation. My instructor had made it seem as though I had initialized 3 separate pointers with malloc (rather than being created by the use of malloc). I then became very confused and tore everything to shreds and started over a few times. Thank you very much for the detailed explanation on how things are used by malloc and free. I was not understanding the way malloc would behave after I set my pointer to a member of a struct. Also thanks for the very informative way of how to use NULL correctly, I researched a lot and must have misinterpreted syntax on SO. – Donner May 24 '17 at 06:14
  • Also your explanation really cleared up how I view the free() function. Really helped me understand the code I was writing in a very straight-forward way. – Donner May 24 '17 at 06:28