I have a singly linked list struct and a local Node declared in main with my addToList() function, but every time addToList() executes it runs the case (head == NULL). Even when I already added values to the list. I am sure there is a small bug in my code, I just can't find it.
typedef struct node{
char* name;
int groupSize;
int status;
struct node* next;
}Node;
void addToList(char* name, Node* head, int groupSize, int status){
if(head == NULL){
head =(Node*)malloc(sizeof(Node));
head->name = (char*) malloc(sizeof(char)*30);
strcpy(head->name, name);
head->groupSize = groupSize;
head->status = status;
head->next = NULL;
printf("Name is %s\n\n", head->name);
}
else {
printf("entered else\n");
Node *tmp = head;
if(tmp->next!=NULL){
tmp = tmp->next;
}
tmp->next = (Node*) malloc(sizeof(Node));
tmp->next->name = (char*) malloc(sizeof(char)*30);
strcpy(tmp->next->name, name);
tmp->next->groupSize = groupSize;
tmp->next->status = status;
tmp->next->next = NULL;
}
}
int main(){
Node* head = NULL;
//TESTNG SECTION
addToList("Julio", head, 5, 7);
addToList("Francisco", head, 5, 7);
addToList("Jorge", head, 5, 7);
}
The cause of your problem is the call by value of every C function call.
At the first call of addToList(), head of the main() points to NULL.
Inside the addToList() you change the parameter head to point to a newly allocated memory region. Unfortunately, by the time addToList() returns the scope of the parameter head does not exist any more. So the head variable at the main, has exactly the same value prior the addToList() call.
The solution to this problem would be the use of double pointer for the head, or return and assign at every call the head of the list. So because previous answer covered the one solution, I will provide the other.
Node* addToList(char* name, Node* head, int groupSize, int status){
if(head == NULL){
head =(Node*)malloc(sizeof(Node));
head->name = (char*) malloc(sizeof(char)*30);
strcpy(head->name, name);
head->groupSize = groupSize;
head->status = status;
head->next = NULL;
printf("Name is %s\n\n", head->name);
}
else {
printf("entered else\n");
Node *tmp = head;
if(tmp->next!=NULL){
tmp = tmp->next;
}
tmp->next = (Node*) malloc(sizeof(Node));
tmp->next->name = (char*) malloc(sizeof(char)*30);
strcpy(tmp->next->name, name);
tmp->next->groupSize = groupSize;
tmp->next->status = status;
tmp->next->next = NULL;
}
return head;
}
int main(){
Node* head = NULL;
//TESTNG SECTION
head = addToList("Julio", head, 5, 7);
head = addToList("Francisco", head, 5, 7);
head = addToList("Jorge", head, 5, 7);
}
The head parameter will be initialized inside the function, you have to pass a pointer to a Node pointer :
void addToList(char* name, Node** head, int groupSize, int status);
Then :
*head =(Node*)malloc(sizeof(Node));
Explanations by Manos.
There are a few small problems that I see with your code.
First, I would use different names when passing in the head pointer. It might be confusing the compiler on where to look. Also, when you pass in a node pointer in addToList, you need to dereference it, so instead pass in Node**, and initialize a pointer within the method.
Second, in your addToList method, you have the following condition:
if(tmp->next!=NULL){
tmp = tmp->next;
}
this will only work when you have 2 elements in your list. Instead, make it a while loop, like so:
while(tmp->next!=NULL){
tmp = tmp->next;
}
This will correctly place the tmp pointer at the end of your list.
Hopefully this will fix some bugs,
Related
I'm having a hard time to understand why I'm having an infinite loop while I try to traverse a linked list I made to practice :
#include <stdio.h>
#include <stdlib.h>
typedef struct noeud {
int val;
struct noeud *next;
} noeud;
noeud* add_first(noeud* head, int val){
noeud* p = malloc(sizeof(noeud));
if(p == NULL){
puts("ERROR ALLOCATING NODE ");
exit(-1);
}
else{
p->val = val;
p->next = head;
}
return p;
}
void discover(noeud* head){
noeud* current = head;
while(current != NULL){
printf("---|%d|-|%p|---",current->val, current->next);
current = head->next;
}
}
int main(){
noeud* head = malloc(sizeof(noeud));
head->next = NULL;
head = add_first(head, 5);
head = add_first(head, 4);
head = add_first(head, 3);
head = add_first(head, 8);
discover(head);
return 0;
}
Here's what I did : I created a function like push to add nodes at first, each one will link to the previous one, I'm updating head to take the first node each time I push something new .
Then I'm just trying to print the result and the adresse of the next node, to do so, I used a while loop and I would verify for the NULL condition, I believe the problem is that after updating head, then head->next is not NULL anymore, but I can't really find a way to keep the last element point to null .
In the beginning of your function, you copied the head pointer to a stack variable, noeud* current = head;, but then inside the while loop you assign the stack variable to the next member of head, current = head->next;.
This will just lead to continuous assignment to the same next address and never moves current just switch it to this:
current = current->next;
It looks strange how you allocate memory for a "head node", you don't need to do that. All you need is a single HEAD pointer like so noeud* head = NULL;.
Your main() becomes:
int main(){
noeud* head = NULL;
head = add_first(head, 5);
head = add_first(head, 4);
head = add_first(head, 3);
head = add_first(head, 8);
discover(head);
return 0;
}
Then you have to modify your printing function as per the Josh Weinstein answer:
void discover(noeud* head){
noeud* current = head;
while(current != NULL){
printf("---|%d|-|%p|---\n",current->val, current->next);
current = current->next;
}
}
I am starting to learn C, and trying to implement linked lists. For some reason, my code is not running correcting. My addtail and printlist functions work fine, but my addhead does not.
I cannot figure out what is wrong. Here is the code I have written so far:
#include <stdio.h>
int main()
{
typedef struct temp_node{
int data;
struct temp_node * next;
} node;
void addtail(node * head, int taildata){
node * tail = malloc(sizeof(node));
tail->data = taildata;
tail->next = NULL;
node * current = head;
while(current->next != NULL){
current = current->next;
}
current->next = tail;
}
void addhead(node ** head, int headdata){
node * newhead = malloc(sizeof(node));
newhead->data = headdata;
newhead->next = *head;
*head = newhead;
}
void printlist(node * head){
node * current = head;
while(current != NULL){
printf("%d\n", current->data);
current = current->next;
}
}
node * head = malloc(sizeof(node));
head->data = 0;
head->next = NULL;
addtail(head, 1);
addtail(head, 2);
addhead(head, 5);
printlist(head);
return 0;
}
When I run it (on https://www.tutorialspoint.com/compile_c_online.php) I get the following output:
6299760
1
2
Why is this not changing the head of the list correctly?
I now have another one: Why in addtail I passed the list normally and it worked fine, whereas with addhead I have to pass it by reference?
Both of the ways work fine. Either you pass pointer to node like this:
addhead(node * head, int headdata)
and call it like this:
addhead(head,5)
Or pass a pointer to pointer to a node (2D pointer) :
addhead(node ** head, int headdata)
and call it by passing a reference of pointer to head (i.e. a 2D pointer) this way:
addhead(&head,5)
I hope it helps!
Following is the code for making a linked list which has 2 pointers. Linked list is getting created (printed) and all pointers (prev + next) are fine. But when I call the function "copay" and assign its value(pointer) to "duplicate", I am getting segmentation fault but if I use only "copay" and don't assign it to any other variable then there is no issue.
typedef struct node {
int data;
struct node *next;
struct node *prev;
} node;
void insert(node **head, int data) {
node *new = (struct node *)malloc(sizeof(node));
new->data = data;
new->next = NULL;
node *temp = *head;
if (!(temp)) {
*head = new;
new->prev = NULL;
// printf("\n return : %d",data);
return;
}
while (temp->next)
temp = temp->next;
temp->next = new;
new->prev = temp;
// printf("\n return : %d",data);
}
void print(node **head) {
node *temp = *head;
printf("\n");
while (temp) {
printf(" %d ->", temp->data);
temp = temp->next;
}
printf(" NULL\n");
}
node *copay(node **head) {
node *temp = *head;
return temp;
}
int main() {
node *head;
insert(&head, 1);
insert(&head, 3);
insert(&head, 5);
insert(&head, 7);
insert(&head, 9);
(head)->prev = (head)->next->next;
(head)->next->next->prev = (head)->next->next->next->next;
(head)->next->next->next->next->prev = (head)->next;
print(&head);
node *duplicate = copay(&head);
// print(&duplicate);
}
There is a very simple problem in function main():
node *head;
head is defined but not initialized. You must initialize it to NULL for insert() to function properly, otherwise you have undefined behaviour. Incidentally, it is confusing to name insert a function that actually appends a node to a list. Change this line to:
node *head = NULL;
I do not understand you you are trying to achieve with these lines:
(head)->prev = (head)->next->next;
(head)->next->next->prev = (head)->next->next->next->next;
(head)->next->next->next->next->prev = (head)->next;
The rest looks fine to me.
copay() is actually fine while it is running. The problem happens to its caller(here it is main function) after copay() exits. copay() returns a pointer to a node, but the problem is that the local node, temp, is allocated only while copay() is running. When copay() exits, all of its locals are deallocated. So the caller is left with a pointer to a deallocated node.
I would refer you to go through Section 2 of Pointers and Memory from Stanford CS Education Library which is on Local Memory.
Source: Pointers and Memory
Below is my node struct declaration and my insert at the back function. In main, I declare a head node and point it to NULL. Then I call the function, and try to print out the value of the first node but my program stops. I still can't figure out what is wrong.
typedef struct node {
int val;
struct node *next;
} NODE;
void insert_back(NODE *head, int val) {
NODE *new = malloc(sizeof(NODE));
new->val = val;
new->next = NULL;
if (head == NULL)
head = new;
else {
NODE *p = head;
while (p->next != NULL)
p = p->next;
p->next = new;
}
}
int main() {
NODE *head = NULL;
insert_back(head, 2);
printf("%d", head->val);
}
The pointer which you allocate in insert_back is lost when you get out of your function. In order for this to work, your insert_back should get pointer-to-pointer.
typedef struct node {
int val;
struct node *next;
} NODE;
void insert_back(NODE **head, int val) {
NODE *new = malloc(sizeof(NODE));
new->val = val;
new->next = NULL;
if (*head == NULL)
*head = new;
else {
NODE *p = *head;
while (p->next != NULL)
p = p->next;
p->next = new;
}
}
int main() {
NODE *head = NULL;
insert_back(&head, 2);
printf("%d", head->val);
}
You need to pass the address of the head and not just head. Instead of call by value use call by reference
should be something like insert_back(&head, 2);
And in definition change to void insert_back(NODE **head, int val) {
C passes everything by value. You're passing head, which is a null-pointer (as in value NULL) to the insert_back function.
This NULL is assigned to the head argument-variable of that value.
You're altering that variable, which is local to the insert_back function, which is fine, but don't expect to be altering the variable in the main function, too.
There's 2 possible approaches:
Either add a second level of indirection (pass a pointer to the variable you want to alter), or return the head variable, and reassign:
pointer-to-pointer:
void insert_back(NODE **head, int val)
{
NODE *node = malloc(sizeof *node);
if (node == NULL)//check if malloc was successful!
exit(1);//or fprintf(stderr, "message"); and handle the issue
node->val = val;
node->next = NULL;
if (*head == NULL)
{
*head = node;
return;
}
NODE *tmp = *head;
while (tmp->next != NULL)
tmp = tmp->next;
tmp->next = node;
}
Call this function as you are doing now, but pass the address of the pointer, rather than the pointer itself:
NODE *head = malloc(sizeof *head);
if (head == NULL) exit (1);
head->next = NULL;
insert_back(&head, 123);
Returning head:
NODE * insert_back(NODE *head, int val)
{
NODE *node = malloc(sizeof *node);
if (node == NULL) exit (1);
node->val = val;
node->next = NULL;
if (head == NULL)
{
return node;//head is null, no need to assign
}
NODE *tmp = head;
while (tmp->next != NULL)
tmp = tmp->next;
tmp->next = node;
return head;//return node passed initially, because it will be reassigned!
}
//call like so:
head = insert_back(head, 123);
As an added bonus, you can use this function to allocate a new struct, too:
NODE *head = insert_back(NULL, 123);//pass null pointer, will return new node and assign it to head
But, equally valid:
NODE *head = insert_back(NULL, 123);
head = insert_back(head, 456);
head = insert_back(head, 789);
printf("Head: %d\nNext: %d\nTail: %d\n",
head->val,
head->next->val,
head->next->next->val
);
Of course, don't forget to write a decent function to free your linked lists.
Perhaps, if you haven't written this already, here's a basic example (again: both methods can be used, but I'd recommend the pointer-to-pointer approach):
void free_list(NODE **list)
{
if (*list->next == NULL)
{//tail
free(*list);
*list = NULL;//assign NULL, makes a valid NULL pointer
return;
}
free_list(&(*list->next));//recursive call
//once we get here, all next-nodes are freed:
free(*list);//free node, and again:
*list = NULL;//make a valid null pointer
}
//call:
free_list(&head);
free(head);//will not be a problem, head is NULL pointer
Alternatively:
void * free_list(NODE *list)
{//note VOID POINTER is returned (will always return NULL, though)
if (list->next == NULL)
{
free(list);
return NULL;
}
free_list(list->next);
free(list);//free node, and again:
return NULL;//make a valid null pointer
}
//call
head = free_list(head);
free(head);//not an issue here
So both are equally safe, you might think, but what if you forget to assign the return value of the second free_list function?
free_list(head);
free(head);//<--X undefined behaviour
The memory head points to has already been freed, but you're calling free a second time. That's going to give you grief: the head pointer is invalid, passing an invalid pointer to free results in undefined behaviour. That's why the first (pointer-to-pointer) approach is the safer option: The function, once written, will never forget to assign NULL to the pointer.
As an asside, a couple of tips:
your main function doesn't return an int. compile this code with -Wall and fix that issue by adding a return 0; statement.
Check the return value of all functions, including malloc & co, if the allocation failed, it will return NULL. You're not checking for that, so there is a risk of undefined behaviour there.
I have implemented a short linked list code to add to the beginning of the list.
However the head always contained NULL. I really couldn't get why its behaving in this way. Any help is appreciated ! Below is the code :
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int iData;
struct node *next;
} Node;
void add2Beg(Node* head, int num);
int main(int argc, char const *argv[])
{
Node *head = NULL;
add2Beg(head, 5);
if (head == NULL)
printf("nothing in head !!!\n");
else{
printf("not null\n");
}
add2Beg(head, 15);
return 0;
}
//adds to the beginning of the linked list
void add2Beg(Node* head, int num)
{
//create a temporary location to hold the new entry
Node* temp = (Node *)malloc(sizeof(Node));
temp->iData = num;
if(head == NULL)
{
head = temp;
printf("inside add2Beg\n");
printf("%d\n", head->iData);
head->next = NULL;
printf("exiting add2Beg\n");
}
else
{
temp->next = head;
printf("%p\n", temp->next);
head = temp;
}
}
Because the head variable inside of add2Beg() is local to that function. Assigning a new pointer value to it (head = temp;) only changes the head variable inside the function. You need to pass in a pointer-to-pointer:
void add2Beg(Node** head, int num)
Then use *head inside the function:
if(*head == NULL)
{
*head = temp;
Be careful about lines like head->next = NULL; -- this should be rewritten as (*head)->next = NULL; or (**head).next = NULL;.
And so on. Then call the function like so:
add2Beg(&head, 15);
Because you never assigned head to anything other than NULL...
//here you set it to NULL then pass it to your function
Node *head = NULL;
add2Beg(head, 5);
here in your function you pass in a copy of "head"
void add2Beg(Node* head, int num)
{
//create a temporary location to hold the new entry
Node* temp = (Node *)malloc(sizeof(Node));
temp->iData = num;
if(head == NULL) //we'll get in here
At this point you assign temp to it, so within the scope of this function it's something vaid, but once you leave this function it's back to NULL.
You passed in a copy of the pointer "head" and called it "head". You need to either return the value and assign it in main() or pass a pointer to head into this function in order for the value to be updated.
Solutions:
Node *head = NULL;
head = add2Beg(head, 5);
Node* add2Beg(Node* head, int num){
...
return head;
OR
Node *head = NULL;
add2Beg(&head, 5);
void add2Beg(Node** head, int num){
...
Your function add2beg is not returning the new head in the case when it's modified. Change your function to:
Node * add2Beg(Node* head, int num)
and return the head at the end:
return head;