C newbie here, and I can't seem to figure this one out. So I'm starting to implement a linked-list (just something basic so I can wrap my head around it) and I've hit a snag. The program runs fine, but I can't free() the data stored in my struct.
Here's the source:
#include <stdio.h>
#include <stdlib.h>
struct node {
struct node* next;
void* data;
size_t data_size;
};
typedef struct node node;
node* create_node(void* data, size_t size)
{
node* new_node = (node*)malloc(sizeof(node));
new_node->data = (void*)malloc(size);
new_node->data = data;
new_node->next = NULL;
return new_node;
}
void destroy_node(node** node)
{
if(node != NULL)
{
free((*node)->next);
//this line here causes the error
free((*node)->data);
free(*node);
*node = NULL;
printf("%s\n", "Node destroyed!");
}
}
int main(int argc, char const *argv[])
{
float f = 4.325;
node *n;
n = create_node(&f, sizeof(f));
printf("%f\n", *((float*)n->data));
if (n->next == NULL)
printf("%s\n", "No next!");
destroy_node(&n);
return 0;
}
I get this message in the program output:
malloc: *** error for object 0x7fff5b4b1cac: pointer being freed was not allocated
I'm not entirely keen on how this can be dealt with.
This is because when you do:
new_node->data = data;
you replaces the value put by malloc just the line before.
What you need is to copy the data, see the function memcpy
node* create_node(void* data, size_t size)
...
new_node->data = (void*)malloc(size);
new_node->data = data;
Here, (1) you are losing memory given by malloc because the second assignment replaces the address (2) storing a pointer of unknown origin.
Number two is important because you can't guarantee that the memory pointed to by data was actually malloced. This causes problems when freeing the data member in destroy_node. (In the given example, an address from the stack is being freed)
To fix it replace the second assignment with
memcpy (new_node->data, data, size);
You also have a potential double free in the destroy_node function because the next member is also being freed.
In a linked list, usually a node is freed after being unlinked from the list, thus the next node shouldn't be freed because it's still reachable from the predecessor of the node being unlinked.
While you got an answer for the immediate problem, there are numerous other issues with the code.
struct node {
struct node* next;
void* data;
What's up with putting * next to type name? You are using it inconsistently anyway as in main you got node *n.
size_t data_size;
};
typedef struct node node;
node* create_node(void* data, size_t size)
{
node* new_node = (node*)malloc(sizeof(node));
What are you casting malloc for? It is actively harmful. You should have used sizeof(*new_node). How about checking for NULL?
new_node->data = (void*)malloc(size);
This is even more unnecessary since malloc returns void * so no casts are necessary.
new_node->data = data;
The bug already mentioned.
new_node->next = NULL;
return new_node;
}
void destroy_node(node** node)
{
if(node != NULL)
{
How about:
if (node == NULL)
return;
And suddenly you get rid of indenation for the entire function.
free((*node)->next);
//this line here causes the error
free((*node)->data);
free(*node);
*node = NULL;
printf("%s\n", "Node destroyed!");
What's up with %s instead of mere printf("Node destroyed!\n")? This message is bad anyway since it does not even print an address of aforementioned node.
Related
I tried to create a program to add elements to a linked list. The elements consist of name and age. But it fails to add without giving me any error. Could you please show me my mistake?
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define MAX 9999
struct data {
char name[MAX];
int age;
struct data *next;
};
void pushHead(struct data **head, struct data **tail, char name[], int age) {
struct data *node = (struct data *)malloc(sizeof(struct data));
strcpy(node->name, name);
node->age = age;
if (*head == NULL) {
node = *head;
node = *tail;
node->next = NULL;
} else {
node->next = *head;
*head = node;
}
}
void view(struct data *head) {
struct data *curr = head;
if (curr == NULL)
printf("No Data\n");
else {
while (curr != NULL) {
printf("%s(%d)\n", curr->name, curr->age);
curr = curr->next;
}
}
}
int main(int argc, char const *argv[]) {
struct data *head = NULL;
struct data *tail = NULL;
pushHead(&head, &tail, "Felix", 19);
view(head);
return 0;
}
Output : No Output
My code is working when I put the head on global scope (by changing all the functions to work globally), but when I try to put the head in main scope it doesn't work.
In pushHead(), you are doing:
node = *head;
node = *tail;
this end up assigning NULL to node pointer because *head and *tail both are NULL. Note that this is a memory leak as your program loose the memory reference which the node pointer is holding. Instead, you should do
*head = node;
*tail = node;
Some suggestions:
For storing name in the list node, you are taking buffer of size
9999 (MAX macro) which is (IMO) very large. I believe, a buffer
of size 256 is more than enough for this purpose. Or, you can also
have buffer of exact size required for storing name by allocating
the memory dynamically to it. For this , you have to take a char *
member instead of char array for name and allocate memory to it
dynamically based on size of name parameter of pushHead() and in
this case, you need to make sure to free it explicitly when deleting
the list nodes.
When using strcpy() to copy string, make sure that destination
buffer is large enough to contain the source string to avoid
overflows.
Follow good programming practice. Always check malloc return and
ensure to free the allocated memory once you are done with it.
Do not cast the malloc return.
To include standard library header files use <>, i.e. #include "stdio.h" -> #include <stdio.h>, check this.
Here is my code in question
#include <stdio.h>
#include <stdlib.h>
typedef struct _node Node;
typedef void* Data;
struct _node
{
Data* data;
Node *next;
};
typedef struct _singleLinkedList SingleLL;
struct _singleLinkedList
{
Node *head;
Node *tail;
Node *current; //not used in this example
};
typedef struct _partls
{
int x;
int y;
}Parts;
Node *addhead(SingleLL *list, Data* data)
{
Node *newnode = (Node*)malloc(sizeof(Node));
if(newnode == NULL)
return NULL;
newnode->data = data;
if(list->head == NULL)
{
newnode->next = NULL;
list->tail = newnode;
}
else
{
newnode->next = list->head;
}
list->head = newnode;
return newnode;
}
typedef void(*DISPLAY)(void*);
void displayparts(Parts* part)
{
puts("part_x\t\tpart_y");
printf("%d\t\t%d\n",part->x, part->y);
putchar('\n');
}
void displaySingleLinkedList(SingleLL *list, DISPLAY display)
{
Node *current;
for(current = list->head; current != NULL; current = current->next)
display(current->data);
}
void initSLList(SingleLL *list)
{
list->head = NULL;
list->tail = NULL; //not used in this example
}
int main(void)
{
puts("\nlinked list test code");
SingleLL *sLinkedList;
//create an object
Parts *part1 = (Parts*) malloc(sizeof(Parts));
if(part1 == NULL)
{
puts("NULL");
exit(1);
}
part1->x = 32;
part1->y = 98;
//create one more object
Parts *part2 = (Parts*) malloc(sizeof(Parts));
if(part2 == NULL)
{
puts("NULL");
exit(1);
}
part2->x = 42;
part2->y = 18;
initSLList(&sLinkedList);
addhead(&sLinkedList, part2);
addhead(&sLinkedList, part1);
displaySingleLinkedList(&sLinkedList, (DISPLAY) displayparts);
return 0;
}
Question:
This is a test code, not a complete perfect looking snippet.It has flaws. I did try the debugger to pace it line by line... it breaks when executes the displayparts function, the debugger says: cannot access memory at address 0x0. Although it should be enough info, i think my mind has stalled and i can't figure it out.
Can you help spot the source of the problem/problems that crashes the code? What should i modify to make it work with no errors?
Your pointer handling seems off, in multiple places. Here,
void initSLList(SingleLL *list)
main():
SingleLL *sLinkedList;
initSLList(&sLinkedList);
initSLList is given the address of the pointer sLinkedList, i.e. a pointer to a pointer.
Also, you have
typedef void* Data;
Node *addhead(SingleLL *list, Data* data)
So since Data is a pointer, addhead expects a pointer to a pointer.
But you're giving it a pointer to a Parts structure.
Gcc warns about giving a pointer to an incompatible type in six different places. See what warning options your compiler has, and enable them.
I'd suggest very sparingly typedefing pointers to something that don't look like pointers, just to avoid confusions like this. It might be ok in some library interface though.
SingleLL *sLinkedList;
// ...
initSLList(&sLinkedList);
But initSLList() takes a SingleLL* while you're passing it a SingleLL**. I think you meant to declare sLinkedList as a concrete SingleLL rather than a pointer to one.
You should compile with warnings set to the most verbose level (-Wall in gcc will do the trick). This would have generated a warning for this and possibly other issues in the program. It's a great, although sadly not foolproof, way to protect yourself against the extreme ease of shooting yourself in the foot with C.
I've seen this question in multiple posts but I have yet to find one that has a good explanation for me. Im trying to create a linked list but the struct nor the functions cant be called without getting the error cannot cast to a pointer. Its really bugging me. Any help would be appreciated on how to get this working right. Heres some of the code below thats the issue.
typedef struct node
{
void *data;
struct node *next;
} node;
node *head = NULL;
node* create(void *data, node *next)
{
node *new_node = (node*)malloc(sizeof(node));
if(new_node == NULL)
{
exit(0);
}else{
new_node->data = data;
new_node->next = next;
return new_node;
}
}
node* prepend(node *head, void *data)
{
node *new_node = create(data,head);
head = new_node;
return head;
}
void preload_adz(int adz_fd)
{
struct adz adz_info;
char adz_data[40];
char adz_text[38];
int adz_delay;
char adz_delayS[2];
read(adz_fd,adz_data,40);
strncpy(adz_text,adz_data + 2,40-2);
sprintf(adz_delayS, "%c%c",adz_data[0],adz_data[1]);
adz_delay = atoi(adz_delayS);
adz_info.delay = adz_delay;
strncpy(adz_info.text,adz_text,38);
head = prepend(head, (void*)adz_info); //<---This line throws the error
while(read(adz_fd,adz_data,40) > 0)
{
}
}
struct adz adz_info;
...
head = prepend(head, (void*)adz_info); //<---This line throws the error
The problem here is adz_info is not a pointer, it's the actual struct on the stack. Passing adz_info into a function will copy the struct.
You need a pointer to that struct. Use & to get its address. Once you have the pointer, you don't need to cast it to void pointer, that cast is automatic.
head = prepend(head, &adz_info);
Note that casting is a bookkeeping thing. Casting to void * doesn't turn a struct into a pointer, it says "compiler, ignore the declared type of this variable and just trust me that this is a void pointer".
In a program I'm writing I need a linked list, so it's a pretty specific implementation. It needs:
the ability to add a node to the end
the ability to remove a node whose data matches a specified value
The data is a cstring, no more than 20 characters in length. I'm not very experienced with C and am getting errors with the following signature void addToEnd(llist root, char entery[51]). I tried replacing llist with node but then the error is "unknown type name node". How can I get rid of this?
Here's the code
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct node
{
char entery[51];
struct node* next;
} llist;
/*may be losing root address permanently*/
void addToEnd(llist root, char entery[51])
{
while(root->next != NULL)
root = root->next;
node last = malloc(sizeof(struct node));
root->next = last;
strcpy(last, entery);
}
int main()
{
struct node *root = malloc(sizeof(struct node));
root->next = NULL;
strcpy(root->entery, "Hello");
struct node *conductor = root;//points to a node while traversing the list
if(conductor != 0)
while(conductor->next != 0)
conductor = conductor->next;
/* Creates a node at the end of the list */
conductor->next = malloc(sizeof(struct node));
conductor = conductor->next;
if (conductor == NULL)
{
printf( "Out of memory" );
return EXIT_SUCCESS;
}
/* initialize the new memory */
conductor->next = NULL;
strcpy(conductor->entery, " world\n");
addToEnd(root, " at the");
addToEnd(root, " end");
/*print everything in list*/
conductor = root;
if(conductor != NULL)
{
while(conductor->next != NULL)
{
printf("%s", conductor->entery);
conductor = conductor->next;
}
printf("%s", conductor->entery);
}
return EXIT_SUCCESS;
}
One thing I'm unclear about, is in all the examples I've seen is they typedef the struct. Why? Let me elaborate: how do you know if you want to be passing just node or struct node. Also I don't really see the point, struct node isn't that much longer than a single typedef'd name.
Problems:
line 12: void addToEnd(llist root, char entery[51]) shall be void addToEnd(llist *root, char entery[51]). Here root must be a pointer type or you actually can not modify its value inside the function and make it visible outside the function.
line 16: node last = malloc(sizeof(struct node)); shall be struct node *last = malloc(sizeof(struct node));. Since in C you must reference a type name with the keyword struct, and also it shall be a pointer or it cannot be initialized with malloc.
As for your typedef question, I believe it is optional and people use it only for convenience. Personally I don't use typedef on a struct very often.
EDITED:
Also your code comes with bugs. Sorry I was only focusing on the syntax before.
Please notice that malloc in C don't assure you that the allocated memory is zeored, it's actually could be anything inside. So you need to fill it manually: to add a line last->next = NULL; at the end of addToEnd.
To refer to your struct of the linked list, use struct node, after the typedef, you can also use llist. You can also ues, as the linked question uses.
typedef struct node
{
char entery[51];
struct node* next;
} node;
In this style, you can use node the same as struct node.
The syntax error you are facing is, you misused the arrow operator ->, it's used with pointers of struct. For struct, use the dot operator .
So for the function
void addToEnd(llist root, char entery[51])
{
while(root->next != NULL)
root = root->next;
You should pass in a pointer:
void addToEnd(llist* root, char entery[51])
Consider the following code snippet
struct node {
char *name;
int m1;
struct node *next;
};
struct node* head = 0; //start with NULL list
void addRecord(const char *pName, int ms1)
{
struct node* newNode = (struct node*) malloc(sizeof(struct node)); // allocate node
int nameLength = tStrlen(pName);
newNode->name = (char *) malloc(nameLength);
tStrcpy(newNode->name, pName);
newNode->m1 = ms1;
newNode->next = head; // link the old list off the new node
head = newNode;
}
void clear(void)
{
struct node* current = head;
struct node* next;
while (current != 0)
{
next = current->next; // note the next pointer
/* if(current->name !=0)
{
free(current->name);
}
*/
if(current !=0 )
{
free(current); // delete the node
}
current = next; // advance to the next node
}
head = 0;
}
Question:
I am not able to free current->name, only when i comment the freeing of name, program works.
If I uncomment the free part of current->name, I get Heap corruption error in my visual studio window.
How can I free name ?
Reply:
#all,YES, there were typos in struct declaration. Should have been char* name, and struct node* next. Looks like the stackoverflow editor took away those two stars.
The issue was resolved by doing a malloc(nameLength + 1).
However,If I try running the old code (malloc(namelength)) on command prompt and not on visual studio, it runs fine.
Looks like, there are certain compilers doing strict checking.
One thing that I still do not understand is , that free does not need a NULL termination pointer, and chances to overwrite the allocated pointer is very minimal here.
user2531639 aka Neeraj
This is writing beyond the end of the allocated memory as there is no space for the null terminating character, causing undefined behaviour:
newNode->name = (char *) malloc(nameLength);
tStrcpy(newNode->name, pName);
To correct:
newNode->name = malloc(nameLength + 1);
if (newNode->name)
{
tStrcpy(newNode->name, pName);
}
Note calling free() with a NULL pointer is safe so checking for NULL prior to invoking it is superfluous:
free(current->name);
free(current);
Additionally, I assume there are typos in the posted struct definition (as types of name and next should be pointers):
struct node {
char* name;
int m1;
struct node* next;
};