I have been trying to free the allocated memory of a file loaded into a linked list, I have managed to free the nodes, but I can't figure out how to free the allocated memory of the file's values copies.
I have tried something like that:
void FreeString(struct node * newNode)
{
for (int i = 0; i < 5; i++)
{
free(newNode->string);
}
}
but the compiler would crash with a segmentation fault, and valgrind would still point out to memory leaks.
it would be appreciated if anyone can tell me what am I doing wrong, and point me to the right direction.
Full code:
The struct:
typedef struct node
{
char *string;
struct node *next;
}node;
// main function here...
void Push(struct node **RefHead, char *word)
{
struct node *newNode = NULL;
newNode = (struct node *)malloc(sizeof(node));
newNode->string = (char*)malloc(strlen(word) + 1); // can't free this part here
strcpy(newNode->string, word);
newNode->next = *RefHead;
*RefHead = newNode;
}
Loading the file into memory:
void FileToNode()
{
struct node *head = NULL, *current = NULL;
infile = fopen("file.txt", "r");
if (infile == NULL)
{
printf("Could not open file\n");
exit(1);
}
while (fgets(word, sizeof(word), infile))
{
Push(&head, word);
}
fclose(infile);
current = head;
while(current)
{
printf("%s", current->string);
current = current->next;
}
freeAll(head);
}
The Free function:
void freeAll(struct node *head)
{
struct node *current = NULL;
while ((current = head) != NULL)
{
head = head->next;
free(current);
}
}
Am I missing something? What's wrong with:
void freeAll(struct node *head)
{
struct node *current = NULL;
while ((current = head) != NULL)
{
head = head->next;
free(current->string);
free(current);
}
}
It's not the problem, but you should probably replace:
newNode->string = (char*)malloc(strlen(word) + 1); // can't free this part here
strcpy(newNode->string, word);
with:
newNode->string = strdup (word);
The problem is this:
void FreeString(struct node * newNode)
{
for (int i = 0; i < 5; i++)
{
free(newNode->string);
}
}
Once you call free, newNode->string no longer points to an allocated object (because you just freed it). So you can't pass it to free again.
Related
I have a problem with this code. I have tried to debug with gdb and Valgrind, But nothing works...
The goal of the code is to create a list, where every string is added only if no existing node with the same string in already part of the list.
This is the code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct node {
char *word;
struct node *next;
};
void print_list(struct node *head) {
while ((head) != NULL) {
printf(" %s -> ", head->word);
head = (head->next);
}
}
// insert a new node in head
void add_n(struct node **head, char *str) {
struct node *new;
new = malloc(sizeof(struct node));
if (new == NULL) {
printf("Not enough memory\n");
exit(EXIT_FAILURE);
}
new->word = str;
new->next = NULL;
if ((*head) == NULL){
(*head) = new;
}
while ((*head)->next != NULL) {
head = &(*head)->next;
}
(*head)->next = new;
}
// check if str is present in the list
int find_string(struct node **head, char *str) {
int found = 0;
while ((*head) != NULL) {
int i = strcmp(str, (*head)->word); //i=0 are the same
if (i == 0) {
found = 1;
return found;
}
head = &((*head)->next);
}
return found;
}
// insert a new string in the list only if is new
void insert(struct node **head, char *str) {
if (find_string(head, str) == 0) {
add_n(head, str);
}
}
void rem_ent(struct node **head, struct node *ent) {
while ((*head) != ent) {
head = &((*head)->next);
}
(*head) = ent->next;
free(ent);
}
void fini_list(struct node **head) {
while ((*head) != NULL) {
rem_ent(head, *head);
head = &((*head)->next);
}
}
int main() {
struct node *head = NULL;
insert(&head, "electric");
print_list(head);
insert(&head, "calcolatori");
print_list(head);
insert(&head, "prova pratica");
print_list(head);
insert(&head, "calcolatori");
print_list(head);
fini_list(&head);
//printf("lunghezza media = %f\n", avg_word_lenght(head));
return 0;
}
Maybe the error might be stupid, but I spent a lot of time debugging without success.
the function fini_list invokes undefined behavior due to the redundant statement
head=&((*head)->next);
because the function rem_ent already set the new value of the pointer head.
void rem_ent(struct node** head, struct node * ent){
while((*head) != ent){
head= &((*head)->next);
}
(*head)= ent->next;
free(ent);
}
Remove the statement
void fini_list(struct node** head){
while((*head) != NULL){
rem_ent(head, *head);
}
}
Also change the function add_n the following way
// insert a new node in head
void add_n(struct node ** head, char* str){
struct node * new;
new = malloc(sizeof(struct node));
if (new == NULL) {
printf("Not enough memory\n");
exit(EXIT_FAILURE);
}
new->word= str;
new->next = NULL;
if ((*head)==NULL){
(*head)=new;
}
else
{
while((*head)->next != NULL){
head = &(*head)->next;}
(*head)->next = new;
}
}
And next time format the code such a way that it would be readable.
In general you should allocate dynamically memory for strings that will be stored in nodes of the list.
I was trying to free memory for a linked list iteratively. The list has a struct which looks like this, and in this linked list, I don't add a url if it's in this list.
struct Node {
char *url;
struct Node *next;
};
Once done working with this linked list, I tried to free it, but got segmentation fault, I'm still in the way of learning c, I haven't got much clue of how to debugging such error other than directly searching for related topics. Referenced a few SOs this one, this one and this one, still cannot figure out where it got crashed.
Here's my code. Free feel to add comments if you think anything I missed in this implementation.
void url_push(struct Node *head, const char *url, size_t url_size) {
struct Node *new_node = (struct Node *) malloc(sizeof(struct Node));
new_node->url = malloc(url_size);
new_node->next = NULL;
for (int i = 0; i < url_size; i++)
*(new_node->url + i) = *(url + i);
struct Node *current = head;
while(1) {
if (strcmp(current->url, new_node->url) == 0) {
printf("Seen page %s!!!!!\n", new_node->url);
free(new_node);
break;
} else if (current->next == NULL) {
current->next = new_node;
break;
} else {
current = current->next;
}
}
}
int main() {
struct Node *head = (struct Node*)malloc(sizeof(struct Node));
head->url = "/";
head->next = NULL;
char *url = "www.google.com";
url_push(head, url, strlen(url));
url = "www.yahoo.com";
url_push(head, url, strlen(url));
url = "www.google.com";
url_push(head, url, strlen(url));
url = "www.wsj.com";
url_push(head, url, strlen(url));
struct Node *current = NULL;
while ((current = head) != NULL) {
printf("url: %s\n", head->url);
head = head->next;
free(current->url);
free(current);
}
}
Edited:
To reduce the confusions, I revised the struct. The purpose of using strcmp is to avoid adding a url that already seen.
head->url = "/";
That is not malloced data so you can't free it!
Your other problem is in url_push() with new_node->url = malloc(url_size); which does not allocate enough space for the terminating 0 in the string (nor does it copy the terminating 0 so you end up not "stomping on memory" but do have unterminated strings...). Try new_node->url = strdup(url); instead.
Style wise: calculate url_size in url_push() instead of making each caller call strlen() do it once inside the function being called (note if you use strdup() then you don't need the url_size at all.
Final note: A tool like valgrind would find both of these problems easily.
There are multiple problems in your code:
you do not allocate space for the null terminator for the new_node->url strings in url_push, causing strcmp() too have undefined behavior.
the first node is not properly constructed: its url pointer is not allocated.
you so not check for memory allocation failure
You should make url_push() more generic: it should handle empty lists by returning the new head pointer. You do not need to pass the length of the url string, just use strdup(), and you should avoid allocating a new node before checking for duplicates.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char *url;
struct Node *next;
};
struct Node *url_push(struct Node *head, const char *url) {
struct Node *current = head;
if (current != NULL) {
for (;;) {
if (strcmp(current->url, url) == 0) {
printf("Seen page %s before!!!!!\n", url);
return head;
} else if (current->next == NULL) {
break;
} else {
current = current->next;
}
}
}
struct Node *new_node = malloc(sizeof(struct Node));
if (new_node == NULL || (new_node->url = strdup(url)) == NULL) {
fprintf(stderr, "memory allocation failure\n");
exit(1);
}
new_node->next = NULL;
if (current == NULL) {
head = new_node;
} else {
current->next = new_node;
}
return head;
}
int main() {
struct Node *head = NULL;
head = url_push(head, "/");
head = url_push(head, "www.google.com");
head = url_push(head, "www.yahoo.com");
head = url_push(head, "www.google.com");
head = url_push(head, "www.wsj.com");
while (head != NULL) {
printf("url: %s\n", head->url);
struct Node *current = head;
head = head->next;
free(current->url);
free(current);
}
return 0;
}
Apologies for the very basic question, but I can't figure this out. I am trying to build a simple linked list and append some values to it in C.
Below is the list.c file
#include <stdio.h>
#include <stdlib.h>
#include "./list.h"
int main(int argc, char *argv[]) {
int arr[] = {1,2,3,4};
List *list = createList();
int i = 0;
for(i = 0; i < 4; i++) {
appendList(list, arr[i]);
}
return 0;
}
List *createList() {
List *list = malloc(sizeof(List));
if(list == NULL) {
return NULL;
}
list->head = malloc(sizeof(Node));
list->tail = malloc(sizeof(Node));
if(list->head == NULL || list->tail == NULL) {
free(list);
return NULL;
}
list->size = 0;
return list;
}
void appendList(List *list, int num) {
if(list->head->value == 0) {
list->head->value = num;
list->tail->value = num;
return;
}
Node *current = calloc(1, sizeof(Node));
current = list->head;
while(current->next != NULL) {
current = current->next;
}
current->next = calloc(1, sizeof(Node));
if(current->next == NULL) {
free(current->next);
printf("Failed to allocate memory");
exit(1);
}
current->next->value = num;
list->size += 1;
list->tail = current->next;
}
And below is the header file
#ifndef List_h
#define List_h
#include <stdlib.h>
typedef struct node {
int value;
struct node *next;
} Node;
typedef struct {
Node *head;
Node *tail;
int size;
} List;
List *createList();
void appendList(List *, int num);
Node *removeList(List *);
void printList(List *);
#endif
While running through a debugger, my code seems to be working fine, which makes even less sense.
I assume my issue is in the while loop inside of appendList, where I am trying to access some unallocated piece of memory. Is the issue then with the check I am making, current->next != NULL? Does accessing an unallocated piece of memory necessary return NULL?
Hmm, well my thoughts are that you've created the initial head and tail Nodes and you didn't set its value. Later you use value to determine whether or not you need to add another node or set head and tail to the value passed:
void appendList(List *list, int num) {
if(list->head->value == 0) {
list->head->value = num;
list->tail->value = num;
return;
}
...
The memory returned from malloc will not be necessarily zero, so your algorithm should ensure that all values are set before proceeding.
You then proceed to reach the end of your list:
Node *current = calloc(1, sizeof(Node));
current = list->head;
while(current->next != NULL) {
current = current->next;
}
However, again, while list->head exists, you never set the value of list->head->next! Following an unassigned pointer is not going to end nicely for you in the best of cases.
Consider creating a method to create a new node:
Node* createNode() {
Node* node = malloc(sizeof(Node));
if(node == NULL) {
return NULL;
}
node->value = 0;
node->next = NULL;
return node;
}
Also please note that there's a minor correction to the code here (unrelated to your segmentation fault, but could still create memory leak):
list->head = malloc(sizeof(Node));
list->tail = malloc(sizeof(Node));
if(list->head == NULL || list->tail == NULL) {
free(list);
return NULL;
}
Note that it is possible for list->head to correctly be assigned memory and list->tail to not be correctly assigned memory. In that case, you risk having a memory leak for list->head. Please take the necessary precautions.
Especially in embedded systems, the code compiled for debug mode and the one for release mode can differ. So, for me, there is no surprise that your code works in debug and won't in release.
When creating linked lists using malloc, it is possible that the compiler sets the address of your "struct node * next" element, a non-accessible location in memory. So if you try to access it, you'll get a segfault. (or BAD_EXC in MacOS)
If you suspect that malloc is your problem, try creating a small list with no malloc and see if you have segfault, i.e. use:
struct node myNode;
struct node* pmyNode = &myNode;
In your while loop, I suppose, you are trying to go to the last element of your list. So, instead of:
while(current->next != NULL) {
current = current->next;
}
Try to do this:
last_linked_list_element->next = last_linked_list_element;
current = first_linked_list_element;
while(current != current->next) {
current = current->next;
}
You will break out of the loop when you are at the last element of your list.
Another solution would be to try:
last_linked_list_element->next = NULL;
or
last_linked_list_element->next = &random_identifier;
This will make sure that the pointer locates to an accesible location in memory. Does this solve your problem?
In addition to the previous post, in the following code:
Node *current = calloc(1, sizeof(Node));
current = list->head;
while(current->next != NULL) {
current = current->next;
}
you should to delete the line Node *current = calloc(1, sizeof(Node)); because in this way you allocate memory and than don't use it (subsequently you assign currect pointer to another value).
I'm having a problem with inserting a node at the end of a linked list. It's not being executed when the start node is not null and I don't understand the problem. Please help me out here. The function is called second time but is not going to the else block.
typedef struct token_Info
{
int linenumber;
char* token;
char value[200];
struct token_Info* next;
} token_Info;
token_Info *tokenlist;
token_Info* insert_at_end( token_Info *list,char *name)
{
printf("token identified \t");
token_Info *new_node;
token_Info *temp,*start;
start = list ;
char *tempname ;
tempname = name;
new_node= malloc(sizeof(token_Info));
new_node->token = malloc(sizeof(strlen(tempname)+1));
strcpy(new_node->token,tempname);
new_node->next= NULL;
// printf("%d",strlen(tempname));
if(new_node == NULL){
printf("nFailed to Allocate Memory");
}
if(start==NULL)
{
start=new_node;
return start;
}
else
{
printf("anvesh");
temp = start;
while(temp->next != NULL)
{
temp = temp ->next;
}
temp->next = new_node;
return temp;
}
}
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
tokenlist = insert_at_end(tokenlist,"TK_BEGIN1");
UPDATE
I found two bugs, the first was the head of the list was not being returned when appending the list. The other in the memory allocation for the token string which incorrectly used sizeof.
I repositioned the test of the malloc() return value, and added a second one. I removed several unnecessary temporary variables that were cluttering the code. I added two functions, show_list() and free_list(). Finally, remember that the value string field is still uninitialised.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct token_Info
{
int linenumber;
char* token;
char value[200];
struct token_Info* next;
} token_Info;
token_Info* insert_at_end( token_Info *list, char *name)
{
token_Info *new_node, *temp;
new_node= malloc(sizeof(token_Info));
if(new_node == NULL){ // repositioned
printf("\nFailed to allocate node memory\n");
exit(1); // added
}
new_node->token = malloc(strlen(name)+1); // removed sizeof
if(new_node->token == NULL){ // added
printf("\nFailed to allocate token memory\n");
exit(1);
}
strcpy(new_node->token, name);
new_node->next= NULL;
if(list==NULL)
return new_node;
// append
temp = list;
while(temp->next != NULL)
temp = temp->next;
temp->next = new_node;
return list; // original head
}
void free_list( token_Info *list)
{
token_Info *temp;
while (list) {
temp = list->next;
free(list->token);
free(list);
list = temp;
}
}
void show_list( token_Info *list)
{
printf ("\nCurrent list:\n");
while (list) {
printf ("%s\n", list->token);
list = list->next;
}
}
int main(int argc, char **argv)
{
token_Info *tokenlist = NULL;
tokenlist = insert_at_end(tokenlist, "TK_BEGIN");
show_list(tokenlist);
tokenlist = insert_at_end(tokenlist, "TK_SECOND");
show_list(tokenlist);
tokenlist = insert_at_end(tokenlist, "TK_FINAL");
show_list(tokenlist);
free_list(tokenlist);
return 0;
}
Program output:
Current list:
TK_BEGIN
Current list:
TK_BEGIN
TK_SECOND
Current list:
TK_BEGIN
TK_SECOND
TK_FINAL
The question could also be whether you want tokenlist to be a running end of the list, or remain at the start.
As of right now, your first call:
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
has tokenlist being the only node in the list.
The second call tokenlist = insert_at_end(tokenlist,"TK_BEGIN1"); returns 'temp' which happens to also be the 'TK_BEGIN' node, ( ie, the first node )
If you want the return value to be the last element, you would return new_node instead of temp. If you want to retain the start, you would return start;
All that said:
The calls to it are not part of any function,
I just ran it with the calls in main and got this output:
int main(void){
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
tokenlist = insert_at_end(tokenlist,"TK_BEGIN1");
return 0;
}
$> ./a.out
token identified token identified anvesh
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct strqueue {
struct lnode *front;
struct lnode *back;
int length;
};
struct lnode {
char *item;
struct lnode *next;
};
StrQueue create_StrQueue(void) {
struct strqueue *sq = malloc(sizeof(struct strqueue));
sq->length = 0;
sq->front = NULL;
sq->back = NULL;
return sq;
}
void destroy_nodes(struct lnode *l) {
while (l!=NULL) {
struct lnode *c = l;
l=l->next;
free(c);
}
}
void destroy_StrQueue(StrQueue sq) {
destroy_nodes(sq->front);
free(sq);
}
void sq_add_back(StrQueue sq, const char *str) {
struct lnode *n = malloc(sizeof(struct lnode));
n->item = malloc(sizeof(char)*(strlen(str)+1));
strcpy(n->item, str);
n->next = NULL;
if (sq->length == 0) {
sq->front = n;
sq->back = n;
} else {
sq->back->next = n;
sq->back = n;
}
sq->length++;
}
char *sq_remove_front(StrQueue sq) {
if (sq->front == NULL) {
return NULL;
} else {
struct lnode *f = sq->front;
char *temp = sq->front->item;
sq->front = sq->front->next;
sq->length--;
//Delete the line below will not cause an error of not free all memory
free(f->item);
free(f);
return temp;
}
}
int sq_length(StrQueue sq) {
return sq->length;
}
Here I wanna make the strqueue like a linked list but when I use it, it always says that I am attempting to double free something. Which part of my code is wrong? Is there a memory leak or something wrong about the memory allocation?
In
struct lnode *f = sq->front;
char *temp = sq->front->item;
sq->front = sq->front->next;
sq->length--;
//Delete the line below will not cause an error of not free all memory
free(f->item);
free(f);
return temp;
It returns pointer temp to freed memory in free(f->item), reading the string through that pointer is undefined behaviour. And if you free it that is going to be the double free. Basically, the returned pointer is useless.
The fix would be to avoid doing free(f->item) in that function. The caller would need to free the pointer to the string after use.
Singly-linked list is best represented by:
struct lnode *head, **tail;
Initialized as:
head = NULL;
tail = &head;
In this case there is no need for special handling of an empty list on appending. Appending always is:
*tail = n;
tail = &n->next;
Removing from the front is:
struct lnode *n = head;
if(head) {
head = head->next;
if(!head)
tail = &head;
}
return n;
You could try this in char *sq_remove_front(StrQueue sq) :
if (f->item != NULL) {
free(f->item);
f->item = NULL;
}
if (f != NULL) {
free(f);
sq->front = NULL;
}
It would avoid performing free() twice on the pointers.