0

In the following code, I am allocating memory for a few int pointers, setting their data, printing the data information, and freeing them. Then, I allocate data for a new int pointer and print all of the data again.

What I am observing is that the same data is written to new location in memory as well as one of the previously freed locations. I would expect it write to one of the previously free'd locations, but why would it also write to a new location?

By the way, I am working in MS Visual C++ 2010.

Here is the code:

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

int main(int argc, char *argv)
{
    int *ip;
    int *jp;
    int *xp;

    printf("\n   Memory Allocation Test Bench\n")
    printf("----------------------------------\n");

    ip = malloc(sizeof(*ip));
    jp = malloc(sizeof(void *));

    *ip = 10;
    *jp = 20;

    printf("ip Data: %d, Location: %p\n", *ip, &ip);
    printf("jp Data: %d, Location: %p\n", *jp, &jp);

    free(ip);
    free(jp);

    xp = malloc(sizeof(*xp));

    *xp = 40;

    printf("\nAfter freeing all and setting *xp = 40...\n");
    printf("ip Data: %d, Location: %p\n", *ip, &ip);
    printf("jp Data: %d, Location: %p\n", *jp, &jp);
    printf("xp Data: %d, Location: %p\n", *xp, &xp);

    free(xp);

    printf("\nAfter freeing xp...\n");
    printf("ip Data: %d, Location: %p\n", *ip, &ip);
    printf("jp Data: %d, Location: %p\n", *jp, &jp);
    printf("xp Data: %d, Location: %p\n", *xp, &xp);

    printf("\nPress any key to continue... \n");
    getchar();

    return EXIT_SUCCESS;
} // End of Main

And here is the output I am getting, marked to show what I am talking about:

Malloc TB Output

You can see that when *xp is set to 40, two locations in memory seem to be altered. What might be causing this to happen?


UPDATED

After learning that trying to use a freed pointer was undefined behavior, I understand that the output doesn't necessarily have to be explained, given that the actions leading to it are undefined. With that in mind, and based on the answers to this question: What happens to memory after free()? , the freed pointers are still pointing to a location in memory, they just should not be used to access it. Which brings in the debate about Setting variable to NULL after free()? to prevent this issue in the first place.


Mystery Solved

A big thanks to Matt McNabb for pointing out that the printf statements were not printing the address in memory pointed to by the pointers, but were printing the stack address of the pointers themselves. Replacing the printf lines like this:

printf("xp Data: %d, Location: %p\n", *xp, &xp);

with lines like this:

printf("xp Data: %d, Location: %p\n", *xp, xp);

generated this new output which clearly shows everything is working properly. The last malloc() statement recycled the memory previously freed. And since the freed pointer still technically pointed to a valid location in memory, it looked like 2 locations were being altered at the same time:

Malloc() TB take 2

Undefined behavior aside, this explanation at least gives reasoning to what was going on - a very simple (and amateur) coding error. Moral of the story: Take note of the address you are talking about (heap vs stack) and do not try to access memory using a freed pointer.

Community
  • 1
  • 1
Kurt E. Clothier
  • 276
  • 1
  • 11
  • 6
    There are multiple undefined behavior invocations in your program. – ouah Apr 04 '14 at 23:18
  • 1
    There is no such thing as data duplication. If you walk through the code in a debugger, stepping through the assembly, you can explain that is happening. The essential truth though is when you free a buffer, you should not use it again because reading is unreliable and writing can cause serious problems. – mah Apr 04 '14 at 23:24
  • 2
    And among the UB, the logic is also wrong. The "Location" you're printing are the addresses of local variables and has *nothing* to do with the addresses returned from dynamic allocation (and subsequently free'd and dereferenced to trip UB as noted earlier). The values passed there should be the addresses returned, not the addresses of the pointers holding those addresses. Ex: `printf("ip Data: %d, Location: %p\n", *ip, ip);` <== note lack of `&`. – WhozCraig Apr 04 '14 at 23:29
  • It is undefined behaviour to use a pointer that has been `free`d; all bets are off. – M.M Apr 05 '14 at 00:26
  • 1
    @KurtE.Clothier: You are clearly not aware that 'undefined behaviour' is a reference to the C standard, and that once your program contains UB, the standard allows it to do anything at all, including reformatting your hard disk, rebooting the computer, etc. Using a pointer after you freed what it points to is UB. The answer that you accepted was not a good one, because it ignored the UB. As you make more use of SO, you may understand why some of the older hands comment as they do. – david.pfx Apr 05 '14 at 02:41
  • @david.pfx I get what you are saying, it just seems lazy - standard or not. It's like having a button on your TV that when pushed could do anything from change the channel to blow it up. If it is UB, it shouldn't be allowed. But again, that is just the hardware engineer coming out of me. And I know how SO works, I just don't believe anyone in a civilized society should act as they often do. As for the accepted answer, many were quick to comment, but none answered. It also answered my questions rather than just telling me what was wrong. I will give it a day or two, and see what happens. – Kurt E. Clothier Apr 05 '14 at 05:23
  • Comments are not the place for debate. I've opened http://meta.stackexchange.com/questions/228481/is-a-short-cryptic-comment-better-than-none-especially-for-a-newish-user. – david.pfx Apr 05 '14 at 06:25
  • I can answer your question, but you really should fix the UB first. – david.pfx Apr 05 '14 at 06:26
  • What books did you read on C before starting to program in C? – Ian Ringrose Apr 05 '14 at 11:55

1 Answers1

2

There are not "two memory locations altered". I guess you are talking about the output lines:

ip Data: 40, Location: 0012FF60
xp Data: 40, Location: 0012FF3C

However, your "Location" is not where the 40 is stored; it's the location (on the stack) of the pointers ip and xp. To see location where the 40 is stored, output xp, not &xp.

Also, you should cast to (void *) the argument matching a %p format specifier.

It is undefined behaviour to try and print the value of a pointer that has been freed, let alone dereference it (ip or *ip in this case). To print ip reliably, do it before you free it.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • In the "updated" version, you will note that the "matching" values all reside at the same address, i.e. you're outputting the contents of the same address multiple times – M.M Apr 05 '14 at 01:49
  • Your example is showing that when you `free` memory and `malloc` more memory, the freshly allocated memory could be at the same location as the memory that was `free`d before. – M.M Apr 05 '14 at 01:51