Pointer to struct incrementation - c

was implementing a singular linked list in C.
struct node
{
int data;
struct node *next;
};
struct list_el {
int val;
struct list_el * next;
};
typedef struct list_el item;
void main() {
item * curr, * head,*track;
int i;
head = NULL;
for(i=1;i<=10;i++) {
curr = (item *)malloc(sizeof(item));
curr->val = i;
curr->next=0;
if(head!=NULL)
head->next = curr;
head = curr;
}
curr = curr-10;
while(curr) {
printf("%d\n", curr->val);
curr = curr->next ;
}
}
As there are 10 elements in the list, so to make the pointer point to the first element, I tried decreasing curr (pointer to struct) by 10, but this got me half way through the list, the values printed were 5,6,7,8,9,10.
The size of the struct is 4, whereas the size of the pointer is 2, it seems the pointer is decreased by 2*10=20 bytes instead of 40, is this normal? (as I read that pointer increments/decrements according to the size of its type)

You cannot use pointer arithmetic on a linked list: the items are allocated separately (with malloc) and so they will not be necessarily adjacent in memory. That approach would only work with an array.

There are several problems.
First of all, the following insertion code isn't correct:
if(head!=NULL) head->next = curr;
head = curr;
Basically, the element pointed to by head is irrevocably lost.
Secondly, the behaviour of the following code is undefined:
curr = curr-10;
You cannot move across several malloc()ed blocks using pointer arithmetic.
Once you fix the insertion logic, it will become possible to traverse the list like so:
for (curr = head; curr != NULL; curr = curr->next) {
....
}

Your code curr = curr-10 will not bring you back to the head of the linklist.

As Viruzzo pointed out in a comment, you cannot use pointer arithmetic on elements of a linked list. As the word "linked" implies, there are only pointers linking the items together, they're not required to be located at adjacent addresses.
The pointer arithmetic will simply decrease the pointer by a fixed number of bytes, it will not follow pointers. Your list, being singly-linked, doesn't even have previous-element pointers to follow.

curr = curr-10; is wrong. It does not perform the operation that you think it does!
To print the contents of your linked list, you need to start from the head and go through each and every node until you hit NULL (assuming its not a circular list).
void display()
{
NODE * current = head;
if (current == NULL) {
printf("Empty list \n");
return;
}
while(current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
return;
}
And to add new node in the front, you can use the following code snippet.
void addfront(int data)
{
NODE *newnode = NULL;
if ((newnode = malloc(sizeof(NODE))) != NULL) {
newnode->data = data;
newnode->next = NULL;
} else {
printf("Couldn't allocate space for new element \n");
return;
}
if (head == NULL) {
// empty list
head = newnode;
tail = newnode;
} else {
newnode->next = head;
head = newnode;
}
return;
}
To add new node at the rear, you can use the following code snippet.
void addrear(int data)
{
NODE * newnode = NULL;
if ((newnode = (NODE *) malloc(sizeof(NODE))) != NULL) {
newnode->data = data;
newnode->next = NULL;
} else {
printf("unalbe to allocate memory to the new element - %d \n", data);
return;
}
if (tail == NULL) {
assert(head == NULL && tail == NULL);
head = tail = newnode;
} else {
tail->next = newnode;
tail = newnode;
}
return;
}
All the above mentioned code snippet assumes, you have head and tail as global variables.
Hope this helps!

Related

Removing unique elements in a doubly linked list in C

I need a little help removing unique characters in a doubly linked list in C. So here's the logic I tried implementing: I counted the occurrence of each character in the doubly linked list. If it's occurrence is 1 time, then it is unique element and needs to be deleted. I'll be repeating the process for all elements. But my code in remove_unique_dll() function isn't working properly, please help me fix it. Here's my code-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
int len;
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
newNode->data = data;
if (head == NULL)
{ //If dll is empty
head = tail = newNode; //Both head and tail will point to newNode
head->prev = NULL; //head's previous will point to NULL
tail->next = NULL; //tail's next will point to NULL, as it is the last node of the list
}
else
{
tail->next = newNode; //newNode will be added after tail such that tail's next points to newNode
newNode->prev = tail; //newNode's previous will point to tail
tail = newNode; //newNode will become new tail
tail->next = NULL; //As it is last node, tail's next will point to NULL
}
}
void remove_unique_dll()
{
struct node *current = head;
struct node *next;
struct node *prev;
int cnt;
while (current != NULL)
{
next = current->next;
cnt = 1;
//printf("!%c ",next->data);
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if (cnt == 1)
{
prev = current->prev;
//printf("#%c %d",prev->data,cnt);
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
if (next == NULL)
{
tail = prev;
}
else
{
next->prev = prev;
}
}
current = current->next;
//printf("#%c ",current->data);
}
head = current;
}
void display()
{
struct node *current = head; //head the global one
while (current != NULL)
{
printf("%c<->", current->data); //Prints each node by incrementing pointer.
current = current->next;
}
printf("NULL\n");
}
int main()
{
char s[100];
int i;
printf("Enter string: ");
scanf("%s", s);
len = strlen(s);
for (i = 0; i < len; i++)
{
addNode(s[i]);
}
printf("Doubly linked list: \n");
display();
remove_unique_dll();
printf("Doubly linked list after removing unique elements: \n");
display();
return 0;
}
The output is like this-
If you uncomment the printf() statements inside remove_unique_dll() you'll notice that no code below inner while loop is being executed after inner while loop ends. What's the issue here and what's the solution?
Sample input- aacb
Expected output- a<->a<->NULL
Some issues:
You shouldn't assign head = current at the end, because by then current is NULL
The next you use in the deletion part is not the successor of current, so this will make wrong links
As you progress through the list, every value is going to be regarded as unique at some point: when it is the last occurrence, you'll not find a duplicate anymore, as your logic only looks ahead, not backwards.
When you remove a node, you should free its memory.
Not a big issue, but there is no reason to really count the number of duplicates. Once you find the first duplicate, there is no reason to look for another.
You should really isolate the different steps of the algorithm in separate functions, so you can debug and test each of those features separately and also better understand your code.
Also, to check for duplicates, you might want to use the following fact: if the first occurrence of a value in a list is the same node as the last occurrence of that value, then you know it is unique. As your list is doubly linked, you can use a backwards traversal to find the last occurrence (and a forward traversal to find the first occurrence).
Here is some suggested code:
struct node* findFirstNode(char data) {
struct node *current = head;
while (current != NULL && current->data != data) {
current = current->next;
}
return current;
}
struct node* findLastNode(char data) {
struct node *current = tail;
while (current != NULL && current->data != data) {
current = current->prev;
}
return current;
}
void removeNode(struct node *current) {
if (current->prev == NULL) {
head = current->next;
} else {
current->prev->next = current->next;
}
if (current->next == NULL) {
tail = current->prev;
} else {
current->next->prev = current->prev;
}
free(current);
}
void remove_unique_dll() {
struct node *current = head;
struct node *next;
while (current != NULL)
{
next = current->next;
if (findFirstNode(current->data) == findLastNode(current->data)) {
removeNode(current);
}
current = next;
}
}
You have at least three errors.
After counting the number of occurrences of an item, you use next in several places. However, next has been used to iterate through the list. It was moved to the end and is now a null pointer. You can either reset it with next = current->next; or you can change the places that use next to current->next.
At the end of remove_unique_dll, you have head=current;. There is no reason to update head at this point. Whenever the first node was removed from the list, earlier code in remove_unique_dll updated head. So it is already updated. Delete the line head=current;.
That will leave code that deletes all but one occurrence of each item. However, based on your sample output, you want to leave multiple occurrences of items for which there are multiple occurrences. For that, you need to rethink your logic in remove_unique_dll about deciding which nodes to delete. When it sees the first a, it scans the remainder of the list and sees the second, so it does not delete the first a. When it sees the second a, it scans the remainder of the list and does not see a duplicate, so it deletes the second a. You need to change that.
Let's consider your code step by step.
It seems you think that in this declaration
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
the both pointers head and tail are explicitly initialized by NULL. Actually only the pointer tail is explicitly initialized by NULL. The pointer head is initialized implicitly as a null pointer only due to placing the declaration in file scope. It to place such a declaration in a block scope then the pointer head will be uninitialized.
Instead you should write
struct node *head = NULL, *tail = NULL; //Represent the head and tail of the doubly linked list
Also it is a very bad approach when the functions depend on these global variables. In this case you will be unable to have more than one list in a program.
Also the declaration of the variable len that is used only in main as a global variable
int len;
also a bad idea. And moreover this declaration is redundant.
You need to define one more structure that will contain pointers head and tail as data members as for example
struct list
{
struct node *head;
struct node *tail;
};
The function addNode can invoke undefined behavior when a new node can not be allocated
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
//...
You should check whether a node is allocated successfully and only in this case change its data members. And you should report the caller whether a node is created or not.
So the function should return an integer that will report an success or failure.
In the function remove_unique_dll after this while loop
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if cnt is equal to 1
if (cnt == 1)
//..
then the pointer next is equal to NULL. And using the pointer next after that like
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
is wrong.
Also you need to check whether there is a preceding node with the same value as the value of the current node. Otherwise you can remove a node that is not a unique because after it there are no nodes with the same value.
And this statement
head = current;
does not make sense because after the outer while loop
while (current != NULL)
the pointer current is equal to NULL.
Pay attention that the function will be more useful for users if it will return the number of removed unique elements.
Here is a demonstration program that shows how the list and the function remove_unique_dll can be defined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct list
{
struct node *head;
struct node *tail;
};
int addNode( struct list *list, char data )
{
struct node *node = malloc( sizeof( *node ) );
int success = node != NULL;
if (success)
{
node->data = data;
node->next = NULL;
node->prev = list->tail;
if (list->head == NULL)
{
list->head = node;
}
else
{
list->tail->next = node;
}
list->tail = node;
}
return success;
}
size_t remove_unique_dll( struct list *list )
{
size_t removed = 0;
for ( struct node *current = list->head; current != NULL; )
{
struct node *prev = current->prev;
while (prev != NULL && prev->data != current->data)
{
prev = prev->prev;
}
if (prev == NULL)
{
// there is no preceding node with the same value
// so the current node is possibly unique
struct node *next = current->next;
while (next != NULL && next->data != current->data)
{
next = next->next;
}
if (next == NULL)
{
// the current node is indeed unique
struct node *to_delete = current;
if (current->prev != NULL)
{
current->prev->next = current->next;
}
else
{
list->head = current->next;
}
if (current->next != NULL)
{
current->next->prev = current->prev;
}
else
{
list->tail = current->prev;
}
current = current->next;
free( to_delete );
++removed;
}
else
{
current = current->next;
}
}
else
{
current = current->next;
}
}
return removed;
}
void display( const struct list *list )
{
for (const node *current = list->head; current != NULL; current = current->next)
{
printf( "%c<->", current->data );
}
puts( "null" );
}
int main()
{
struct list list = { .head = NULL, .tail = NULL };
const char *s = "aabc";
for (const char *p = s; *p != '\0'; ++p)
{
addNode( &list, *p );
}
printf( "Doubly linked list:\n" );
display( &list );
size_t removed = remove_unique_dll( &list );
printf( "There are removed %zu unique value(s) in the list.\n", removed );
printf( "Doubly linked list after removing unique elements:\n" );
display( &list );
}
The program output is
Doubly linked list:
a<->a<->b<->c<->null
There are removed 2 unique value(s) in the list.
Doubly linked list after removing unique elements:
a<->a<->null
You will need at least to write one more function that will free all the allocated memory when the list will not be required any more.

why free function causes infinite loop?

I created a program in c which :
Creates a simple linked list in c in which I store letters
Print the content of every node
delete the last node
Print the content of the list again
The problem is with the "delete_last" function because prints in terminal an infinite loop (I believe that the problem is invoked when I use free funtion.)
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
char xar;
struct node *next;
}Node;
void insert_list(Node **head , int len)
{
char x;
Node **list;
Node *node1 , *node2;
node1=(Node*)malloc(sizeof(Node));
printf("Give 5 characters : ");
x=getchar();
node1->xar = x;
node1->next=NULL;
list=&node1;
int i=0;
for(i=1 ; i < len ; i++)
{ x=getchar();
node2 = (node*)malloc(sizeof(node));
node2->xar = x;
node2->next = NULL;
(*list) -> next = node2;
list = &(*list) -> next ;
}
*head=node1;
}
void print_list(Node *head)
{
Node**lpp;
for(lpp=&head ; *lpp!=NULL ; lpp=&(*lpp)->next)
{
printf("\n the chars are %c" , (*lpp)->xar);
}
}
void delete_last(Node *head)
{
Node **lpp;
lpp=&head;
while((*lpp)->next!=NULL)
{
lpp=&(*lpp)->next;
}
free(*lpp);
}
int main()
{
Node *kefali ;
kefali = NULL;
insert_list(&kefali , 5);
print_list(kefali);
printf("\n");
delete_last(kefali);
print_list(kefali);
return 0;
}
You mustn't access to freed objects.
In the delete_last functon, you called free() for one of the nodes, but you didn't update any pointers there. This will have the following call of print_list access a freed object, invoking undefined behavior.
You should add
*lpp = NULL;
after
free(*lpp);
To get the freed node out of the list.
Note that this won't work for removing the first (only) element in the list because the head is passed as a copy. You should change the function to accept a pointer to the head pointer to enable it remove the first element.
Your delete_last lacks a way of telling that the last element was deleted. Either pass a pointer to head or return a new head.
Further, it's way to complicated. Using lpp as pointer to pointer is not necessary - it only complicates the code. Keep it simple.
Here is an example which returns the new head.
Node* delete_last(Node *head)
{
if (head == NULL) return NULL; // empty list
if (head->next == NULL)
{
// Only one element...
free(head);
return NULL;
}
Node *prev = head;
Node *lpp = prev->next;
while (lpp->next)
{
prev = lpp;
lpp = prev->next;
}
prev->next = NULL;
free(lpp);
return head;
}
and call it like:
head = delete_last(head);
Here is an example which takes a pointer to head.
Node* delete_last(Node **head)
{
if (head == NULL) exit(1); // illegal call
if (*head == NULL) return NULL; // empty list
if ((*head)->next == NULL)
{
// Only one element...
free(*head);
*head = NULL;
return;
}
Node *prev = *head;
Node *lpp = prev->next;
while (lpp->next)
{
prev = lpp;
lpp = prev->next;
}
prev->next = NULL;
free(lpp);
}
and call it like:
delete_last(&head);
You do not update the previous node (you need to keep track on it when iterating)
This makes no sense as you take reference to the local variable head and it does not change the the head of list when last element is deleted.
Node **lpp;
lpp=&head;
To prevent double-pointer function returns the head. Assign it when called. If return value is NULL the last element was deleted
Node *delete_last(Node *head)
{
Node *lpp = NULL, *prev;
if(head)
{
lpp=head -> next;
prev = head;
while(lpp->next)
{
prev = lpp;
lpp = lpp -> next;
}
if(prev == head && lpp == NULL)
{
free(head);
head = NULL; //empty list
}
else
{
free(lpp);
prev -> next = NULL;
}
}
free(lpp);
return head;
}
You can also use double pointer to modify the head when needed:
void delete_last(Node **head)
{
Node *lpp = NULL;
if(head && *head)
{
if(!(*head) -> next)
{
free(*head);
*head = NULL;
}
else
{
lpp = *head;
while(lpp -> next -> next)
{
lpp = lpp -> next;
}
free(lpp -> next);
lpp -> next = NULL;
}
}
}

Why does a linked list with a double pointer cause an error?

I'm asking you a question because the assignment I was doing didn't work out.
The structure is a common link list, declaring the head pointer in the main and passing the address value of the head pointer as a parameter to the function.
The global variable top is used to determine where the current data is located.
The code currently below will detect only errors when executed.
Structure:
struct ListNode{
int data;
struct ListNode* link;
};
int top = 0;
code:
void DisplayList(ListNode** head){
if(*head == NULL){
printf("List = Empty\n");
}
else{
printf("List = ");
for(;(*head) != NULL; *head = (*head)->link){
printf("%d ",(*head)->data);
}
}
printf("\n");
}
void AddList(ListNode** head){
ListNode* temp = (ListNode*)malloc(sizeof(ListNode));
int num;
printf("Data register) ");
scanf("%d",&num);
temp->data = num;
temp->link = NULL;
top++;
if(*head == NULL){
*head = temp;
}
else{
for(;(*head)->link != NULL; *head = (*head)->link){}
(*head)->link = temp;
}
DisplayList(head);
}
the expected result:
Data register) 10
List = 10
Data register) 20
List = 10 20
Data register) 30
List = 10 20 30
You shouldn't modify *head in the loops. You need to use a local variable to step through the list, otherwise you're changing the caller's variable to point to the end of the list.
void DisplayList(ListNode** head){
if(*head == NULL){
printf("List = Empty\n");
}
else{
printf("List = ");
for(ListNode *step = *head;step != NULL; step = step->link){
printf("%d ",step->data);
}
}
printf("\n");
}
void AddList(ListNode** head){
ListNode* temp = (ListNode*)malloc(sizeof(ListNode));
int num;
printf("Data register) ");
scanf("%d",&num);
temp->data = num;
temp->link = NULL;
top++;
if(*head == NULL){
*head = temp;
}
else{
ListNode *step = *head;
for(;step->link != NULL; step = step->link){}
step->link = temp;
}
DisplayList(head);
}
Your error is in how you traverse the list:
for(; (*head)->link != NULL; *head = (*head)->link) {}
At the beginning, *head is the head of the list from the calling function. By assigning to it, you overwrite it continuously, until it becomes null.
Instead, you should assign to head: It holds the address of the head node in the calling function at first and the address of the link pointer of the previous node in subsequent iterations:
for(; (*head)->link != NULL; head = &(*head)->link) {}
After this loop, head holds the address of the pointer where the new node should be stored. Assign the new node to that pointer directly:
*head = temp;
This will update the head pointer of the calling function when the list was empty and the link member of the previous node otherwise. You don't have to treat the case where the list is empty specially.
The insertion function might now look like this:
void AddList(ListNode** head, int num)
{
ListNode* temp = malloc(sizeof(ListNode));
temp->data = num;
temp->link = NULL;
while (*head) head = &(*head)->link);
*head = temp;
}
(In my opinion, reading the input and printing the list shoudl not be part of te insertion function.)
Regarding your printing function: Seeing a function like that:
void DisplayList(ListNode** head)
raises a red flag: Passing a pointer to node pointer signals that you want to modify the list (and you inadvertently do that), but printing the list only inspects it. Change the signature to
void DisplayList(const ListNode* head)
then use head instead of (*head) in the function. (Rule of thumb: If you never use *head = ... somewhere in the list, you don't need a pointer to node pointer.)

Malloc with scope and global variables

#include<stdio.h>
#include<stdlib.h>
struct node {
int num;
struct node *next;
}*head=NULL, *curr=NULL;
void print(){
curr = head;
while(curr != NULL){
printf("%d\n", curr->num);
curr = curr->next;
}
}
struct node* memAlo(){
return (struct node *)malloc(sizeof(struct node));
}
void addNode(int no){
curr = head;
while(curr != NULL){
curr = curr->next;
}
curr = memAlo();
if(curr == NULL){
printf("\nmemory up\n");
return;
}
else{
curr->num = no;
curr->next = NULL;
printf("%d\n",curr->num);
}
}
void hellop(){
printf("%d", head->num);
}
int main(){
int i;
curr = head;
for(i=1;i<10;i++){
addNode(i);
}
print();
/*head = memAlo();
head->num = 1;
head->next = NULL;
hellop();*/
}
I am sure I have messed up somewhere. The thing is that the head pointer doesn't get the memory allocated by the memAlo() fn() but how to get there? Please help
What I am trying is to create a singly linked list holding numbers from 1 to 9 and to print them using print(). Actually AddNode() is to create single node at the end of the linked list each time the for loop in main() executes.
You set head = NULL at the point where you first defined head. Except in that one place, we never see head on the left-hand side of = anywhere in your program. So of course head is always equal to NULL and never anything else.
You will probably want to insert some code at the start of your addNode function to test whether head == NULL at that point; and if that is true, you will want to assign the result of memAlo() to head instead of curr. You will have to adjust some of the other logic as well.
Your code for allocating a node is wrong. It should create a node, make some space for it, then return it.
struct node *memAlo() {
struct node *nd = malloc(sizeof(*nd));
return nd;
}
This creates a pointer to a node, properly allocates it, then returns it.
Problems I see:
Not dealing with empty list, i.e. when head == NULL.
Creating nodes that are not linked to each other.
curr = memAlo();
allocated memory for a node and returns it to you, but it does not connect the node with anything else.
Try this:
void addNode(int no){
struct node* temp = NULL;
// Deal with an empty list.
if ( head == NULL )
{
head = memAlo();
head->num = no;
head->next = NULL;
}
// Move curr until we reach the last node of the list.
curr = head;
while(curr->next != NULL){
curr = curr->next;
}
temp = memAlo();
if(temp == NULL){
printf("\nmemory up\n");
return;
}
else{
// Link the new node to the previous last node.
temp->num = no;
temp->next = NULL;
printf("%d\n",temp->num);
curr->next = temp;
}
}
It seems that since head is initially NULL, and then you start allocating nodes without saving the address of the first one, you lose the address of the first one, and then can't walk the list from the beginning.
The part you commented out illustrate the problem.
As a side note, there is no free in your program. Remember to always free the memory you alloc
#include<stdio.h>
#include<stdlib.h>
struct node
{
int num;
struct node *next;
};
struct node *head, *curr;
struct node *pos;
void addNode(int n)
{
if(head==NULL)
{
head = (struct node*)malloc(sizeof(struct node));
head->num = n;
head->next = NULL;
curr = head;
}
else
{
while(curr != NULL)
{
pos = curr;
curr = curr->next;
}
curr = (struct node*)malloc(sizeof(struct node));
curr->num = n;
curr->next = NULL;
pos->next = curr;
}
}
void printList()
{
curr = head;
while(curr != NULL)
{
printf("%d",curr->num);
curr = curr->next;
}
}
int main()
{
head = NULL;
curr = head;
int i, a[] = {4,5,1,2,3,9,0};
for(i=0;i<7;i++)
{
addNode(a[i]);
}
curr = head;
printList();
}
This seems to have solved my problem. I figured it out though. Thanks for all your help.

Push and append an item into a linked list in C

I have a weird problem. I have this piece of code, but it doesn't work. The weird part is that inside the function, the list is changed (printf commands indicate this), but when call this function, nothing will be added to the list (my list is not empty).
void pushToList(node* list, int val) {
node* newNode = (node*) malloc(sizeof(node));
newNode->value=val;
newNode->next = list;
list = newNode;
printf("here, list->value = %d \n", list->value);
printf("here, list->next->value = %d \n", list->next->value);
}
// ----------------------------------
// if (list==NULL) {
// newNode->next = NULL;
// list = newNode;
// } else {
// newNode->next = list;
// list = newNode;
// }
I call this function for example in my main function like this:
node* node1;
pushToList(node1, 1111);
And here is my struct and typedef in a separate header file (that I have included in my function file):
#ifndef STACKELEMENT_H
#define STACKELEMENT_H
struct stackElement {
int value;
struct stackElement* next;
};
typedef struct stackElement node;
#endif /* STACKELEMENT_H */
Another weird behavior is that I have the following function for appending an item, and this function only works if my list is not empty:
int appendtoList(node* head, int val) {
node* current = head;
node* newNode = (node*) malloc(sizeof (node));
if(newNode == NULL){
fprintf(stderr, "Unable to allocate memory for the new node\n");
exit(-1);
}
newNode->value = val;
newNode->next = NULL;
while (current->next) {
current = current->next;
}
current->next = newNode;
// if (head->next == NULL) {
// head->next = newNode;
// } else {
// while (current->next != NULL) {
// current = current->next;
// }
// current->next = newNode;
// }
//
return 0;
}
use node**list as argument type in your function.
when u pass a pointer to a function like struct node *x to
void max (struct node*p);
the pointer is passed by value AND
if u want to really manipulate the contents to which x points to use struct node** as the argument type and pass &x to the function.
Same logic should apply to your problems.
The problem was with the return type, i.e. the scope of a variable which in this case is a pointer variable. mbratch also pointed out this, thank you very much, but actually before reading mbratch's comment, I suddenly remembered a point from a lecture note about "accessing an object outside of its lifetime" which I think is different from "call by value/call by reference" problem.
Just some clarifications for people who may run into this problem and may get confused:
since we are allocating memory for the struct newNode INSIDE the function pushToList (even though using dynamic memory allocation command), the memory assigned to this variable would be free/destroyed when the function ends and the control returns back to the callee function (in this case, main()). So you should set the return type of your function to node* (a pointer to a node struct) and in your function return the head. Like this:
node* pushToList(node* head, int val) {
node* newNode = (node*) malloc(sizeof(node));
newNode->value=val;
newNode->next = head;
head = newNode;
return head;
}
In appendToList function, in addition to this mistake, as mbracth pointed out, I was doing another mistake by checking head->next (although implicitly) rather than head itself (to see if it's NULL): if head is NULL, you can not access head->next. Indeed two answers marked as the correct answers in some other posts here on stackoverflow misleaded me to this mistake. Anyway, here is the correct way:
if (head == NULL) {
head = newNode;
} else {
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}

Resources