Fail to push head on Linked List - c

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.

Related

Problem using free() in a loop creating a linked list from a file

So I have a file called file.txt and i want to create a linked list from the information it contains, where each line of the file is a new node. So far I have this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct sAirport{
char name;
int number;
struct sAirport *next;
}tAirport;
tAirport *createNode(tAirport *newNode, char str[1000]);
void createLinkedList(tAirport **head, tAiport *newNode);
int main()
{
FILE *fa = fopen("test.txt", r);
char str[1000] = {0};
tAirport *head = NULL;
tAirport *newNode = NULL;
while(fgets(str, sizeof(str), fa) != NULL)
{
newNode = createNode(newNode, str);
createLinkedList(&head, newNode);
free(newNode);
newNode = NULL;
}
return 0;
}
tAirport *createNode(tAirport *newNode, char str[1000])
{
char *aux = NULL;
newNode = malloc(sizeof(tAirport));
if(newNode == NULL)
exit(EXIT_FAILURE);
aux = strtok(str, " ");
strcpy(&newNode->name, aux);
aux = strtok(NULL, " ");
sscanf(aux, "%d", &newNode->number);
newNode->next = NULL;
return newNode;
}
void createLinkedList(tAirport **head, tAirport newNode)
{
tAirport *temp = NULL;
if(*head == NULL)
{
*head = newNode;
return;
}
temp = *head;
while(temp->next != NULL)
temp = temp->next;
temp->next = newNode;
}
I'm getting weird results and Valgrind says I have lost bytes but I don't know what to do.
Edited so that it can run.
For example the file I'm testing with is:
John 33
Mary 42
Peter 12
What should I do?
Aside from all those warning you will get from compiling this. I just want to tell you that you are misunderstanding how malloc(),free(), and pointer work.
First of all, pointer is just an unsigned long, a natural number just like any other number. The difference is that the pointer store the address of the real memory ( in this case is newNode).
In your program, you malloc() to get your memory, asisgn the memory address to newNode, then you tell your list to hold newNode, finally you free it. So you just free the memory you wish to keep, your list now only hold a bunch of address to freed memory.
Solution for this is, get rid of free() while populating your list, and free them later
The sAirport structure is define the name to be one character. However, from the code, looks like the createNode will allow long name (up to 999 characters). When the createNode create the new entry, the strcpy will overwrite data beyond the allocated space, and will likely cause segmentation fault, or "funny" data.
Consider extending name to the proper size, or using dynamic allocation (malloc) for name.

Freeing a pointer (to a void*) inside of a struct

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.

Trouble with signature of function to add node to end of linked list

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])

C - Unable to free memory allocated within a linked list structure

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;
};

Trouble with insertion of C string into linked list

I am writing a program to read a file and then store the data into a linked List.
linkedList.h
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
struct linked_list
{
char *stock_name;
double stock_price;
struct linked_list *next;
};
typedef struct linked_list NODE;
NODE* insert(NODE *head, double stock_price, char *stock_name);
void printList(NODE *head);
linkedList.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
#include"linkedList.h"
void printList(NODE *head)
{
NODE *this = head;
while(this != NULL)
{
printf("stock name:%s , stock price:%lf\n", this->stock_name, this->stock_price);
this = this->next;
}
}
NODE* insert(NODE *head, double stock_price, char *stock_name)
{
NODE *newNode = malloc(sizeof(NODE));
if(head == NULL)
{
newNode->stock_price = stock_price;
newNode->stock_name = stock_name;
head = newNode;
}
else
{
newNode->stock_price = stock_price;
newNode->stock_name = stock_name;
newNode->next = head;
head = newNode;
}
return head;
}
main.c
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "linkedList.h"
NODE *head;
bool headNode = true;
void insertIntoLinkedList(char *stock_name, double stock_price);
int main ( int argc, char *argv[] )
{
head = malloc(sizeof(NODE));
double stock_price;
char stock_name[100];
int stock_name_counter = 0;
**..then I read the file..**
stock_name[stock_name_counter] = '\0'; //to end my C string
stock_name_counter = 0; //this is used for reading char
insertIntoLinkedList(stock_name, stock_price); //I double checked here,the name and price is correct
**......**
printList(head); //**Not the output I want**
fclose( file );
void insertIntoLinkedList(char *m_stock_name, double m_stock_price)
{
if(headNode == true)
{
head = insert(NULL, m_stock_price, m_stock_name);
headNode = false; //this is used to insert data to my linked list for the first time
}
else
{
head = insert(head, m_stock_price, m_stock_name);
}
}
Here is the problem: if the file contains:
YAHOO 120
GOOGLE 10
APPLE 199
my printList() gave me this:
APPLE 120
APPLE 10
APPLE 199
I have been trying to debug for hours and still cannot figure why the name is not stored in my linked list properly(but the price is store properly..)...any help will be appreciate :)
The address of stock_name in main is always constant through out the program and you store that address to newNode->stock_name and so you will always get the last stored string in stock_name.
Modification
NODE* insert(NODE *head, double stock_price, char *stock_name)
{
NODE *newNode = malloc(sizeof(NODE));
newNode->stock_name = malloc(strlen(stock_name)+1);
if(head == NULL)
{
newNode->stock_price = stock_price;
strcpy(newNode->stock_name, stock_name);
head = newNode;
}
else
{
newNode->stock_price = stock_price;
strcpy(newNode->stock_name, stock_name);
newNode->next = head;
head = newNode;
}
return head;
}
Don't forget to free the allocated memory.
You need to make a copy of the string stored in stock_name when you call insert. As is, all the nodes point to the same buffer, and every time you read a new line, you overwrite the buffer. In the end, this means that all of the nodes have the text APPLE because that's the last content that's read into the shared buffer. If you either copy the buffer's contents (instead of just the pointer to the buffer) or allocate a new buffer every time you read from the file, this will be fixed.
Your basic problem is that C does not have a "String" type. A string is simple an array of characters, and an array "decays" to a pointer when used as an argument to a function. Based on the way you're using it, your insert() function should do a second malloc() to allocate storage for the string and use strdup() or similar to store it.
Your other problem is that you've got a logic flaw in the insert() function. You aren't initializing newNode->next if head is NULL. You should be doing newNode->next = head either way. If it's NULL, good. Your list tail will then not be pointing at an indeterminate place.

Resources