Protip on debugging pointers
Draw pictures. Make a box for each instance and an arrow from each non-null pointer. ALWAYS follow the rules listed below. Assuming all memory management is done with malloc and free there are NO exceptions to these rules.
- Every time and only when you do a
malloc you should draw a new box.
- Every time and only when you use
free you should remove (or just cross it over with an X or something) a box.
- Every time you use
free, remove all arrows from that box.
- Every time you assign a pointer to a value, null or non-null, remove the old arrow if it exists.
- Every time and only when you assign a pointer to a non-null value, draw an arrow.
Note: For a typical call to malloc, you would use both rule 1, 4 and 5. Using malloc without taking care of the return pointer means leaking memory.
Note2: Important! You should NOT remove an arrow TO the box you're deallocating when you use free. Only do that when you specifically assign a pointer to null. In the same way, do NOT remove a box when you assign a pointer to null.
Note3: Important! If you free a box, rule 3 says that you should remove all arrows from that box. Do NOT remove any boxes the arrows are pointing to.
Your question
Consider this:
ptr = ptr -> next;
ptr = malloc(sizeof(decks));
The first line has no effect whatsoever, since you are immediately reassigning ptr.
You need something like this:
ptr -> next = malloc(sizeof(decks));
ptr = ptr -> next;
Other remarks
I would recommend using sizeof on the variable rather than the type, like this: ptr->next = malloc(sizeof *(ptr->next)) This is a good habit in general. Take this code:
int *x;
x = malloc(sizeof(int));
Now consider if you want to change the type of the variable x. You would need to change the argument to sizeof in EVERY call to malloc. Using x = malloc(sizeof *x) completely removes this problem.
ptr->nextis uninitialized and certainly not pointing to an existing memory block. Otherwise you wouldn't need the firstmalloceither.