I'm currently tackling the Advent of Code 2022 Day 9 challenge and encountered an unexpected issue with freeing a dynamically allocated linked list in my C program. Although my code runs smoothly without freeing the linked list, adhering to best practices by deallocating the memory leads to unexpected behavior. Previously, similar code utilizing the same linked list freeing function worked flawlessly. I'm puzzled about what could be causing this discrepancy.
Here's a condensed version of the relevant parts of my code: (or you can also see the full code here)
// ... some code ....
void freeLinkList(IntPairNode *linkList) {
while (linkList != NULL) {
IntPairNode *temp = linkList;
linkList = linkList->next;
free(temp);
}
}
int findVisited(IntPair *pairList, const Instruction *instructList) {
// pairList and instructList must be properly terminated.
if (pairList[0].isNull == '\0' || pairList[1].isNull == '\0') {
perror("pairList must have at least 2 elements");
return -1;
}
IntPairNode *linkList = malloc(sizeof(IntPairNode));
linkList->x = 0;
linkList->y = 0;
int linkListLength = 1;
// ...
// freeLinkList(linkList); // problemetic line
return linkListLength;
}
// ... some helper function ....
int main(int argc, char *argv[]) {
FILE *file = NULL;
if (!fileOpener(argc, argv, &file)) {
return 1;
}
Instruction *instructList = buildInstructList(file);
if (instructList == NULL) {
printf("Failed to build instruction list.\n");
return 1;
}
fclose(file);
IntPair pairList1[3];
IntPair pairList2[11];
for (int i = 0; i < 2; i++) {
pairList1[i].x = 0;
pairList1[i].y = 0;
pairList1[i].isNull = 'F';
}
pairList1[2].isNull = '\0';
for (int i = 0; i < 10; i++) {
pairList2[i].x = 0;
pairList2[i].y = 0;
pairList2[i].isNull = 'F';
}
pairList2[10].isNull = '\0';
int visited1 = findVisited(pairList1, instructList);
printf("%d\n", visited1); // always works
int visited2 = findVisited(pairList2, instructList);
printf("%d\n", visited2);
free(instructList);
}
The problem arises specifically in the findVisited
function when attempting to free the linked list using the freeLinkedList
function. However, when I comment out the freeLinkList(linkList)
line, the program runs without any issues, although I'm aware this could lead to memory leaks.
I'd appreciate any insights or suggestions on how to address this memory management issue while ensuring proper deallocation of the linked list.
IntPairNode *linkList = malloc(sizeof(IntPairNode)); linkList->x = 0; linkList->y = 0; int linkListLength = 1; // ... // freeLinkList(linkList); // problemetic line
Note that you have not assigned a value to the next
member of your linkList
struct. This value is indeterminate, which may be NULL
but may also be anything else, so your freeLinkList
function doesn't see that the list only contains one node and ends up trying to dereference an uninitialized pointer, leading to undefined behavior.
To avoid this you could explicit initialize next
.
IntPairNode *linkList = malloc(sizeof(IntPairNode));
linkList->x = 0;
linkList->y = 0;
linkList->next = NULL;
Or you might allocate using calloc
rather than malloc
which initializes the allocated memory to zero.
IntPairNode *linkList = calloc(1, sizeof(IntPairNode));