I am relatively new to the idea of pointers and C, so I apologize if this is a really simple problem. I am trying to free a singly linked list from memory that is created. The singly list is created fine, but I am having trouble free it from memory, I get a segmentation fault. Any ideas where I am going wrong? I need to have separate methods for both freelist and freenode. Avail is a global pointer variable and is part of the code that I'm sure works. The problem exists in free list and I'm just not sure where.
void freelist(olnode **list) {
olnode *ptr = *list;
while (*list != NULL) {
ptr = *list
freenode(&ptr);
ptr = ptr->next;
}
}
void freenode(olnode **ptr) {
if(*ptr != NULL) {
(*ptr)->next = avail;
avail = *ptr;
*ptr = NULL:
}
}
Freenode sets the pointer passed to it to NULL. Afterwards freelist tries to dereference the pointer which is now null. That's where the program crashes.
Besides that, your program doesn't really free any data. It just changes the pointers pointing to the data to point to NULL. That means the memory will stay allocated and isn't available for new data. To mark the memory a pointer points to as no longer needed, you need to call the free() method from the standard library on the pointer which points to it. Setting the pointer to NULL afterwards is not needed, but a good practice to make sure that any subsequent try to access the free'ed memory location results in a predictable crash and not in totally unpredictable behavior.
You need to grab the next pointer from the node before freeing it.
Not this:
freenode(&ptr);
ptr = ptr->next;
but this:
olnode *next = ptr->next;
freenode(&ptr);
ptr = next;
Related
This is part of cs50 pset5 speller. Background is that I load a dictionary into a hash table with linked list and check word against the hash table to decide if that word is in the dictionary, after that I unload the hash table.
When I load the dictionary, I used malloc() and free() to insert a node into the linked list. The result of free() here is that it free the memory allocated to a pointer, but it will not remove the pointee (a node inserted into linked list in this case).
Here is my code:
bool load(const char *dictionary)
{
FILE *inputfile = fopen(dictionary, "r");
if (inputfile == NULL)
{
return false;
}
char tempWord[LENGTH+1];
while (fscanf(inputfile, "%s", tempWord) != EOF)
{
//create a tempNode and make sure
node *tempNode = malloc(sizeof(node));
if (tempNode == NULL)
{
return false;
}
strcpy(tempNode->word, tempWord);
tempNode->next = NULL;
//get the index of this word
int index = hash(tempWord);
//move tempNode to the next node in the linked list
if (table[index]->next != NULL)
{
tempNode->next = table[index];
}
table[index]->next = tempNode;
free(tempNode);
word_count ++;
}
fclose(inputfile);
return true;
}
When I unload the dictionary, I used free() again, but this time without calling malloc() at all. So the elements on the linked list can be freed one after another. The result of free() here is that it 'removes' the node from the linked list.
Here is my code:
bool unload(void)
{
for (int i = 0; i < N; i ++)
{
//freeing linked list, we need two tempNode in order to do this
node *tempPtr = table[i];
while (tempPtr != NULL)
{
node *deletePtr = tempPtr;
tempPtr = tempPtr->next; //move the tempPtr to the next element, so we are note losing the linked list
free(deletePtr); //once we moved the tempPtr to the next element, now we can delete where deletePtr is pointing at
}
}
return true;
}
Although my code was compiled and can run without issue, I am very confused of why free() does different things here.
To summarize my questions:
(1)Am I correct to say that: in 'load', free(tempNode) does not 'erase' what tempNode is pointing to (which is a node in a linked list), but only free the memory allocated to tempNode; in 'unload', however, free(deletePtr) 'erase' both deletePtr and what deletePtr is pointing to (which is a node in a linked list)?
(2) If my observation in (1) is correct, why is free() doing different things here? Is that caused by the fact that load called malloc() and unload didn't?
(3) I understand I have to call free() if I called malloc(), but when malloc() isn't called, what does free() do?
=================================
Edit:
After more research, I realized that in load section, it is unnecessary to free() the memory assigned by malloc(). The reason is, in unload section, by free() each node, I will eventually be able to free the memory assigned before.
(1)Am I correct to say that: in 'load', free(tempNode) does not
'erase' what tempNode is pointing to (which is a node in a linked
list), but only free the memory allocated to tempNode;
The object to which tempNode points is not meaningfully distinguished from the memory occupied by the object to which tempNode points. If that is a block of dynamically allocated memory then you must not attempt to access it after freeing it. Any attempt to do so produces undefined behavior.
The question is thus meaningless. There is no conforming way to tell whether the memory in question has been "erased", because you must not attempt to read it. If you do attempt to read it then the program might behave as if the memory had been overwritten in some way, or it might not. And it might do anything else within its power, too. Crashing the program (eventually) is a popular alternative, but by no means a guaranteed one.
in 'unload',
however, free(deletePtr) 'erase' both deletePtr and what deletePtr is
pointing to (which is a node in a linked list)?
See above.
(2) If my observation in (1) is correct [...]
Observation (1) is not correct.
(3) I understand I have to call free() if I called malloc(), but when
malloc() isn't called, what does free() do?
The free() function has undefined behavior (see above) if it is passed a pointer value that is non-null and was not obtained from a memory allocation function, or one that has already been freed.
This is my function to add a new node using double pointer
void insertBefore(node_t **first)
{
node_t *new = NULL;
new = (node_t *) malloc(sizeof(node_t));
new->next = *first;
*first = new;
free(new);
}
If I use it once, everything seems to work fine. However, if I use it again, my linked-list is messed up. I have the output image below (same thing happened to my function to insert node to any position).
I tried to put some very specific part of the code, so if you suspect that I must have been doing something wrong at other parts, please tell me.
Any idea what did I do wrong?
The output image
Just remove free(new);. Since new and *first have same value, freeing new also frees *first.
Refined code:
void insertBefore(node_t **first)
{
node_t *new = malloc(sizeof(node_t)); //don't cast
if(!new)
{
fputs("Don't have enough memory", stderr);
return;
}
new -> next = *first;
*first = new;
}
It because you are freeing the memory.
free(new);
You are just assigning the value to first.
*first=new;
Now first and new will point to same memory position. Then you are freeing that memory. Remove the line free(new);.
You free the node you had just allocated; whenever you attempt to use it, undefined behavior will occur because *first becomes a Dangling Pointer. The address stored in the pointer is no longer valid after the function free() returns.
Your code needs many improvements
You don't need to initialize new to NULL; probably no problem as this would be optimized.
You don't need to cast malloc() or in general void * to any other pointer type.
You don't check that malloc() was successful; you should check that new is not being assigned NULL which would indicate an error.
You MUST NOT free() the newly allocated pointer; you should free() it when you don't need it anymore and not immediately after allocating it.
You really should improve your code formatting. It was completely unreadable in the original post.
This question already has answers here:
Returning a struct pointer
(6 answers)
returning a local variable from function in C [duplicate]
(4 answers)
Closed 8 years ago.
I'm creating a structure inside a function and then returning its pointer. For some reason I keep getting the same memory address each time.
typedef struct list_type
{
node_t *head;
node_t *tail;
} list_t;
list_t newList() {
list_t list = {NULL, NULL};
list_t *listptr = &list;
printf("newList: %p\n", listptr);
return listptr;
}
Outputs:
newList: 0x7fffb42c8ae0
newList: 0x7fffb42c8ae0
newList: 0x7fffb42c8ae0
What am I doing?...
You are allocating list on the stack, but you're trying to return a reference to it from a function. This is a big no-no in C, since the struct's memory is automatically freed by the compiler when it goes out of scope. If you want memory to persist beyond the scope it is allocated in, you need to use malloc.
Furthermore, list_t and a pointer to it (list_t*) are two different types, and you need to indicate that as such in your function definition.
list_t* newList() {
list_t *listptr = malloc(sizeof(list_t));
printf("newList: %p\n", listptr);
return listptr;
}
However, be careful when using malloc. Since you're allocating memory manually, you'll now need to ensure that you call free on the pointer when you're done with it, or it will leak, since the compiler cannot free the memory for you.
list_t list = {NULL, NULL};
allocates memory on stack. Memory allocated on stack is automatically freed when the variable, list in your case, goes out of scope.
That is why you are getting the same address again and again as memory allocated to list on stack gets freed when program comes out of function newList() and is available for allocation. And, when you call the newList() again, same memory is alloacted again.
You should read about different memory allocations and pay more attention to the compiler warnings.
You're returning a pointer to an object allocated on the stack. If you use the value that the pointer points to in the function that calls newList(), you'll cause undefined behavior to occur.
You should read about malloc() and free().
Your function returns a list_t, a structure type, which is perfectly fine by-value. I see no evidence you're trying to dynamically allocate a list_t, and no evidence you even need to do so.
Lose the pointer stuff for this specific structure type entirely and just do this:
list_t newList()
{
list_t list = {NULL, NULL};
return list;
}
void freeList(list_t lst)
{
// TODO: delete lst nodes by walking lst.head through lst.tail
}
int main()
{
list_t lst = newList();
...
freeList(lst);
}
Don't step into the arena of managing dynamic memory because you can; do it when you need to do so, and in this case, you don't. You obviously need to in order to manage the actual list nodes, but thats a different issue than this one.
I have written a binary search tree, it works fine but I'm not sure whether my program frees all the memories.
here is my definition of the node of a tree
typedef struct node {
int val;
struct node *left, *right;
} nodeOfTree;
I write this function to output the result and free all the nodes, it seems that the answer is right but the memories are not freed.
void outputAndDestroyTree(nodeOfTree *root) {
if (!root) {return;}
outputAndDestroyTree(root->left);
printf("%d ", root->val);
outputAndDestroyTree(root->right);
free(root); // I free this pointer, but after doing that, I can still access this pointer in the main() function
}
Is that mean I can not free a piece of memories in the recursive function? Thank you ~~~~~
Update: Thank you all~
Your code seems okay, but freeing the allocated memory won't magically set it's reference pointer to NULL. Since you didn't set a new value to the pointer, the old address will remain there, untouched. Maybe you can even read from it without crashing, despite it being undefined behavior.
If you want it to be set to NULL after freeing the memory, then just do so. Call outputAndDestroyTree(root->left); then do root->left = NULL;.
Here's the task. It is given a linked list, free all the memory and set head to NULL.
This is my function:
void free_list(struct Node *node)
{
while (node)
{
free(node);
node=node->next;
}
}
It outputs no error, just wont do anything. And another thing, how to check if the memory was freed ?
Hints at what's going wrong rather than sample code since this is homework...
You can't reliably access node after freeing it. Store the value of node->next before freeing.
You're passing the Node pointer by value. If you want to NULL the caller's pointer, use a pointer to a pointer instead.
There is no portable way to check the memory was freed, but you could investigate tools like valgrind if you want to check that no memory has been leaked when your program exits.
Note that you can't check the contents of memory locations to reassure yourself that the memory has been freed. Calling free merely passes ownership of the memory back to the system; it may get reallocated (and its values updated) at any point in future.
You should get the next node before freeing the current one
If you want to assign to the head, you need to pass its address to the function.
void free_list(struct Node **head)
{
struct node *nnode, *cnode;
cnode = *head;
while (cnode)
{
nnode = cnode->next;
free(cnode);
cnode = nnode;
}
*head = NULL;
}
call it like this..,,
free_list(&head);
EDIT:
You are accessing the same node node=node->next; after freeing it, You must have to store next pointer before freeing the node.