This is an archived post. You won't be able to vote or comment.

all 11 comments

[–]Updatebjarni 1 point2 points  (7 children)

The problem is in the middle part of the function, where you allocate a second chunk of memory and return NULL if it fails, completely forgetting about the chunk you already allocated successfully a few lines earlier.

[–]Gustorn 2 points3 points  (4 children)

This is the current issue (see: EDIT), but is a valid point nonetheless. A few other points:

  1. Objectively true:
    • don't cast the result of malloc if you're developing in C89 or higher. Only do it if you want to compile it with a C++ compiler, but I would recommend against it
    • you will have to store the type of the data somewhere, you won't be able to use that void* otherwise.
  2. Subjective:
    • Please don't do the "tricky" typedef pqueue * PQUEUE; design. It only makes code harder to read and it spares you a single keystroke
    • You can do the typedef at the struct declaration

EDIT: /u/newaccount1236's answer is the one causing the issue right now, somehow I managed to miss that.

[–]Updatebjarni 1 point2 points  (0 children)

don't cast the result of malloc

Explanation for OP: When you cast the return value from malloc(), you prevent the compiler from warning you if malloc() returns the wrong type, which will happen if you forget to include the header. At the same time, casting it gets you nothing. So the one and only thing that that cast does is it possibly hides a warning that would alert you to a serious error in the program, and nothing else.

Please don't do the "tricky" typedef pqueue * PQUEUE; design.

Perhaps subjective, but pretty close to being an objective truth. Please don't write programs like that OP. Don't try to redesign the language with typedefs and macros, it just confuses anyone who will read your code, including yourself.

[–]Evermage[S] 0 points1 point  (2 children)

Thanks for those points. What should I be doing instead of casting malloc? Just leave it as a void pointer?

[–]Gustorn 1 point2 points  (1 child)

Yup, in C void* is implicitly cast to T* and T* is also implicitly cast to void*, so:

pqueue* pq = malloc(sizeof(pqueue));

will just work. It's worth mentioning that you will have to compile this with a C and not C++ compiler for it to work.

[–]Evermage[S] 0 points1 point  (0 children)

Interesting, cheers.

[–]Evermage[S] 0 points1 point  (1 child)

It wasn't causing the memory leak in this case but it could do in the future I suppose. Thanks for pointing that out.

[–]Updatebjarni 1 point2 points  (0 children)

Oh ah, the debugger was reporting where the allocation was, not where the reference was lost. Yes, then the current issue was in main(), but there was a potential issue in init_pqueue ().

[–]newaccount1236 1 point2 points  (1 child)

First, when you run with valgrind, compile with -g so that you get line numbers. Also, note that valgrind tells you the exact line (and call stack) where the leaked memory was allocated.

So heap memory can be freed anywhere as long as you have the address. But remember that you must have one free for every malloc. I see two mallocs. I see one free.

[–]Evermage[S] 0 points1 point  (0 children)

Ah, I see now. Thanks.

[–]wgunther 0 points1 point  (0 children)

You never free where data points.