Pointers Linked Lists C Programming - c

I don't get why this isn't working... For example I have this.
struct node {
int data;
struct node* next;
};
static int length(struct node* head) {
Does Stuff
};
void main() (
int i;
struct node* head;
i = length(head);
);
but the code doesn't want to work... I get the wrong output. I'm trying to send the pointer to my functions so that they can have access to the data that I malloc. I will post the full code bellow:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node* next;
};
static int length(struct node* head);
static void push(struct node* head, int data);
static int pop(struct node* head);
static void appendNode(struct node* head, int data);
static struct node *copyList(struct node* head);
static void printList(struct node* head);
/************************************************************
length - return length of a list
************************************************************/
int length(struct node* head) {
int count = 0;
struct node* current = NULL;
current = head;
while (current != NULL) {
current = current->next;
++count;
}
return count;
}
/************************************************************
push - add new node at beginning of list
************************************************************/
void push(struct node* head, int data) {
struct node* new_ptr = NULL;
new_ptr = (struct node*)malloc(sizeof(struct node));
new_ptr->data = data;
new_ptr->next = head;
head = new_ptr;
}
/************************************************************
pop - delete node at beginning of non-empty list and return its data
************************************************************/
int pop(struct node* head) {
int val = 0;
struct node* temp = NULL;
if (head != NULL) {
val = head->data;
temp = head->next;
free(head);
head = temp;
}
return(val);
}
/************************************************************
appendNode - add new node at end of list
************************************************************/
void appendNode(struct node* head, int data) {
struct node* current = NULL;
struct node* previous = NULL;
struct node* new_ptr = NULL;
current = head;
previous = current;
while (current != NULL) {
previous = current;
current = current->next;
}
new_ptr = (struct node*)malloc(sizeof(struct node));
new_ptr->data = data;
new_ptr->next = NULL;
previous = new_ptr;
}
/************************************************************
copyList - return new copy of list
************************************************************/
struct node* copyList(struct node* head) {
struct node* copy = NULL;
struct node* current = NULL;
struct node* new_ptr = NULL;
/* Copy current head to copy */
current = head;
while (current != NULL) {
appendNode(copy, current->data);
current = current->next;
}
return copy;
}
/************************************************************
printList - print linked list as "List: < 2, 5, 6 >" (example)
************************************************************/
void printList(struct node* head) {
struct node* current = NULL;
printf("List: < ");
current = head;
if (current == NULL)
printf("none ");
while (current != NULL) {
printf("%d", current->data);
current = current->next;
if (current != NULL)
printf(", ");
}
printf(" >\n");
}
void main() {
int i; // index used for loops
struct node *list_a; // a new list
struct node *list_a_copy; // copy of list
list_a = NULL; // initialize empty list
list_a_copy = NULL; // initialize empy list
// test push
for (i = 0; i < 4; ++i)
push(list_a, i);
// test length
printf("Length of list = %d\n", length(list_a));
// test print head list
printf("head:\n");
printList(list_a);
// test append node
for (i = 4; i < 8; ++i)
appendNode(list_a, i);
// test print head list
printf("head(append):\n");
printList(list_a);
// make a copy of list
list_a_copy = copyList(list_a);
// test pop head list
for (i = 0; i < 4; ++i)
printf("%d popped\n", pop(list_a));
// test print copy list
printf("head copy:\n");
printList(list_a_copy);
// test pop copy list
for (i = 0; i < 4; ++i)
printf("%d popped\n", pop(list_a_copy));
}
Thank you for you help. I'm still learning these C pointers, and I know I'm close.
Cheers

I looked into function push():
void push(struct node* head, int data) {
struct node* new_ptr = NULL;
new_ptr = (struct node*)malloc(sizeof(struct node));
new_ptr->data = data;
new_ptr->next = head;
head = new_ptr;
}
The way you assign head = new_ptr; is wrong. Doing so only, head has effect within in the function, head won't be pointed to the memory you allocated after push() is called. So you need to fix your push() function:
void push(struct node **head, int data) {
if ((*head) == null)
(*head) = (struct node*)malloc(sizeof(struct node));
(*head)->data = data;
(*head)->next = head;
}

The problem is that you are passing a pointer to a node in your methods. This means that what you are modifying is a local parameter and not what you are passing to the method. Why is this? Because passing by value copies the parameter, to the address is directly copied.
struct Node *list_a = NULL;
push(list_a, 5);
When you call push, what happens is that a copy of the variable list_a is pushed onto the stack and then the function is called. The same thing, if you think about it, happens with simple cases:
int x = 5;
add(x, 5);
void add(int a, int b) { a += b; } // <-- this won't modify the x passed
So here
void push(struct Node *head, int value) {
head = something;
}
you are not modifying the original list_a but rather a copy of it which has been passed to the function.
To be able to modify the original pointer you need to pass the address to it, so a pointer to the pointer of the head of the list. This can be done easily:
struct Node *list_a = NULL;
push(&node, 5);
void push (struct Node **node, int value) {
...
*node = malloc(..);
}
So here the address of the variable list_a is passed to the function, dereferencing it allows you to modify the real value instead that just a copy.

Related

I'm having a problem creating a linked list [duplicate]

This question already has answers here:
Linked lists - single or double pointer to the head
(3 answers)
What is the reason for using a double pointer when adding a node in a linked list?
(15 answers)
Closed 10 months ago.
#include<stdio.h>
#include<stdlib.h>
void insert_front(struct node* head, int block_number);
void insert_rear(struct node* head, int block_number);
void print_list(struct node* head);
struct node {
int block_number;
struct node* next;
};
int main(void)
{
struct node* list = NULL;
insert_front(list, 10);
insert_rear(list, 20);
insert_front(list, 30);
insert_rear(list, 40);
print_list(list);
return 0;
}
void insert_front(struct node* head, int block_number)
{
struct node* p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = head;
head = p;
return head;
}
void insert_rear(struct node* head, int block_number)
{
struct node* p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = NULL;
if (head == NULL) {
head = p;
}
else {
struct node* q = head;
while (q->next != NULL) {
q = q->next;
}
q->next = p;
}
}
void print_list(struct node* head)
{
struct node* p = head;
while (p != NULL) {
printf("--> %d ", p->block_number);
p = p->next;
}
printf("\n");
}
When I ran it, there was no result at all.
Now, in the insert_front function p->block_number = block_number, a message appears saying that the NULL pointer 'p' is being dereferenced... (The same thing appears in the insert_rear function.)
Could it be that I am declaring the pointer wrong?
Both insert_front and insert_rear need to convey possibly head modification back to the caller, and the caller needs to reap that information. Both should be declared to return struct node *, do so, and the code in main react accordingly. E.g.:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
struct node * insert_front(struct node *head, int block_number);
struct node * insert_rear(struct node *head, int block_number);
void print_list(struct node *head);
struct node
{
int block_number;
struct node *next;
};
int main(void)
{
struct node *list = NULL;
list = insert_front(list, 10);
list = insert_rear(list, 20);
list = insert_front(list, 30);
list = insert_rear(list, 40);
print_list(list);
return 0;
}
struct node *insert_front(struct node *head, int block_number)
{
struct node *p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = head;
head = p;
return head;
}
struct node *insert_rear(struct node *head, int block_number)
{
struct node *p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = NULL;
if (head == NULL)
{
head = p;
}
else
{
struct node *q = head;
while (q->next != NULL)
{
q = q->next;
}
q->next = p;
}
return head;
}
void print_list(struct node *head)
{
struct node *p = head;
while (p != NULL)
{
printf("--> %d ", p->block_number);
p = p->next;
}
printf("\n");
}
Output
--> 30 --> 10 --> 20 --> 40
I leave the memory leaks for you to resolve.
In C all variables are passed by value – if you pass a pointer, then it is copied, too (not the pointed to object, of course...), and function parameters, apart from being initialised from outside, are nothing more than local variables. Thus via head = p; you just assign the local copy of the outside pointer, not the latter itself!
To fix that you have two options:
Return the new head and make the user responsible for re-assigning the returned value to his own head pointer.
Accept the head as pointer to pointer.
With second approach a user cannot forget to re-assign the (potentially) new head, so that's what I'd go with:
void insert_whichEver(node** head, int block_number)
{
// use `*head` where you had `head` before...
}
void demo()
{
node* head = NULL;
insert_front(&head, 1012);
}
And in insert_front drop return head;, a function with void cannot return anything concrete and does not require a return at all (but bare return; can be used to exit a function prematurely).

Linked List elements not getting displayed

This is my program in C which always inserts into a linked list at the end. But when I try to print the list elements, nothing is displayed. Here is the code :
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int data;
struct Node *next;
};
void insert(struct Node *, int);
int main(void)
{
struct Node *head = NULL, *current;
int n, i, x, data;
scanf("%d", &n);
for(i = 0; i < n; i++)
{
scanf("%d", &data);
insert(head, data);
}
current = head;
while(current != NULL)
{
printf("%d ", current->data);
current = current->next;
}
}
void insert(struct Node *head, int data)
{
struct Node *newnode, *current = head;
newnode = (struct Node *)malloc(sizeof(struct Node));
newnode->data = data;
newnode->next = NULL;
if(head == NULL)
{
head = newnode;
}
else
{
while(current->next != NULL)
{
current = current->next;
}
current->next = newnode;
}
}
I cannot understand what might be the issue. Please help.
Your insert cannot modify head. Change it to
void insert(struct Node **head, int data)
and change it by
*head = newnode;
and call it like this
insert(&head, data);
Here, while you are passing the head pointer to your insert() function, it is not being updated in your main() function.
So, either declare your head pointer as global or return your head pointer and update it in your main() function.
In the below code I had taken the head pointer as global and removed the head pointer as your parameter from the insert() function.
Here is the code :-
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int data;
struct Node *next;
};
struct Node *head=NULL;
void insert(int);
int main(void)
{
struct Node *current;
int n, i, x, data;
clrscr();
scanf("%d", &n);
for(i = 0; i < n; i++)
{
scanf("%d", &data);
insert(data);
}
current = head;
while(current != NULL)
{
printf("%d \n", current->data);
current = current->next;
}
getch();
return 0;
}
void insert(int data)
{
struct Node *newnode, *current = head;
newnode = (struct Node *)malloc(sizeof(struct Node));
newnode->data = data;
newnode->next = NULL;
if(head == NULL)
{
head = newnode;
}
else
{
while(current->next != NULL)
{
current = current->next;
}
current->next = newnode;
}
}
You need to pass the reference of the head pointer, then only the changes made to it will be visible.
You must declare your function like
void insert(struct Node **, int);
and also call it like
insert(&head, data);
also, make changes to function definition
void insert(struct Node **head, int data)
{
struct Node *newnode, *current = *head;
newnode = (struct Node *)malloc(sizeof(struct Node));
newnode->data = data;
newnode->next = NULL;
if(*head == NULL)
{
*head = newnode;
}
else
{
while(current->next != NULL)
{
current = current->next;
}
current->next = newnode;
}
}
You need to pass the head by reference as you are making changes to it that should be visible.
insert(head, data);
should become
insert(&head, data);
Also the function signature will change.
void insert(struct Node *head, int data)
should become
void insert(struct Node **head, int data)
Also make appropriate changes in the function.
Like,
current = *head;
Because you are passing the pointer by value. The function operates on a copy of the pointer, and never modifies the original.
Either pass a pointer to the pointer (i.e. a struct head **), or instead have the function return the pointer.
You can try running the following code which will give the output as null
printf("%s",head);
while(current != NULL)
{
printf("%d", current->data);
current = current->next;
}

Doubly Linked List Error

So, I'm trying to do operations in a doubly linked list, and I tried applying the logic of deletion but it's showing some sort of void error. Please tell me what's wrong in this code.
The error message is written alongside the line of code.
Function to get new node:
void getnewnode(int x)
{
struct node* temp = (struct node*)malloc(sizeof(struct node*));
temp->data = x;
temp->next = NULL;
temp->prev = NULL;
}
Insert function:
void insertatbeg(int x)
{
struct node* newnode=getnewnode(x); /* void value not ignored as it ought to be. */
if(head==NULL)
{
head = newnode;
}
else
{
head->prev = newnode;
newnode->next = head;
head = newnode;
}
}
Delete(nth node) function:
void delete(int n)
{
struct node* temp1=head;
int i;
if(temp1 == NULL)
return;
for(i = 0; i < n-2; i++)
{
temp1 = temp1->next;
}
struct node* temp2 = temp1->next;
(temp2->next)->prev = temp1;
temp1->next = temp2->next;
free(temp2);
}
Here is the main function:
struct node /* List called node */
{
struct node* next;
int data;
struct node* prev;
};
struct node* head;
void insertatbeg(int x);
void delete(int n);
int main()
{
int x;
head = NULL;
insertatbeg(x);
insertatbeg(x);
insertatbeg(x);
delete(2);
}
Looks to me your problem is here:
void getnewnode(int x)
{
struct node* temp = (struct node*)malloc(sizeof(struct node*));
temp->data = x;
temp->next = NULL;
temp->prev = NULL;
}
Specifically, in the first line. You probably want that to be sizeof(struct node), so that your pointer references a node, not a pointer to a node.
You also need to make your function return a value. So change it to:
void getnewnode(int x)
{
....
return temp;
}
The reason you're getting the error on this line:
struct node* newnode=getnewnode(x); /* void value not ignored as it ought to be. */
Is that your getnewnode function doesn't return a value. So newnode can't be assigned a value. That error should go away when you make the suggested change to getnewnode().

Pointers Linked Lists C

Did I do this right? I'm getting a strange error here...
linked.c: In function ‘push’:
linked.c:50:19: warning: assignment from incompatible pointer type [enabled by default]
linked.c: In function ‘main’:
linked.c:146:9: error: incompatible type for argument 1 of ‘push’
linked.c:45:6: note: expected ‘struct node **’ but argument is of type ‘struct node’
~/swen250/CLinkedList$ gcc -o linked linked.c
linked.c: In function ‘push’:
linked.c:50:19: warning: assignment from incompatible pointer type [enabled by default]
~/swen250/CLinkedList$ gcc -o linked linked.c
linked.c: In function ‘pop’:
linked.c:63:19: error: request for member ‘data’ in something not a structure or union
linked.c:64:20: error: request for member ‘next’ in something not a structure or union
linked.c: In function ‘copyList’:
linked.c:106:9: warning: passing argument 1 of ‘appendNode’ from incompatible pointer type [enabled by default]
linked.c:75:6: note: expected ‘struct node **’ but argument is of type ‘struct node *’
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node* next;
};
static int length(struct node** head);
static void push(struct node** head, int data);
static int pop(struct node** head);
static void appendNode(struct node** head, int data);
static struct node *copyList(struct node** head);
static void printList(struct node** head);
/************************************************************
length - return length of a list
************************************************************/
int length(struct node** head) {
int count = 0;
struct node* current = NULL;
current = *head;
while (current != NULL) {
current = current->next;
++count;
}
return count;
}
/************************************************************
push - add new node at beginning of list
************************************************************/
void push(struct node** head, int data) {
struct node* new_ptr = NULL;
new_ptr = (struct node*)malloc(sizeof(struct node));
new_ptr->data = data;
new_ptr->next = *head;
*head = new_ptr;
}
/************************************************************
pop - delete node at beginning of non-empty list and return its data
************************************************************/
int pop(struct node** head) {
int val = 0;
struct node* temp = NULL;
if (*head != NULL) {
val = head->data;
temp = head->next;
free(head);
*head = temp;
}
return(val);
}
/************************************************************
appendNode - add new node at end of list
************************************************************/
void appendNode(struct node** head, int data) {
struct node* current = NULL;
struct node* previous = NULL;
struct node* new_ptr = NULL;
current = *head;
previous = current;
while (current != NULL) {
previous = current;
current = current->next;
}
new_ptr = (struct node*)malloc(sizeof(struct node));
new_ptr->data = data;
new_ptr->next = NULL;
previous = new_ptr;
}
/************************************************************
copyList - return new copy of list
************************************************************/
struct node* copyList(struct node** head) {
struct node* copy = NULL;
struct node* current = NULL;
struct node* new_ptr = NULL;
/* Copy current head to copy */
current = *head;
while (current != NULL) {
appendNode(copy, current->data);
current = current->next;
}
return copy;
}
/************************************************************
printList - print linked list as "List: < 2, 5, 6 >" (example)
************************************************************/
void printList(struct node** head) {
struct node* current = NULL;
printf("List: < ");
current = *head;
if (current == NULL)
printf("none ");
while (current != NULL) {
printf("%d", current->data);
current = current->next;
if (current != NULL)
printf(", ");
}
printf(" >\n");
}
void main() {
int i; // index used for loops
struct node *list_a; // a new list
struct node *list_a_copy; // copy of list
list_a = NULL; // initialize empty list
list_a_copy = NULL; // initialize empy list
// test push
for (i = 0; i < 4; ++i)
push(&list_a, i);
// test length
printf("Length of list = %d\n", length(&list_a));
// test print head list
printf("head:\n");
printList(&list_a);
// test append node
for (i = 4; i < 8; ++i)
appendNode(&list_a, i);
// test print head list
printf("head(append):\n");
printList(&list_a);
// make a copy of list
list_a_copy = copyList(&list_a);
// test pop head list
for (i = 0; i < 4; ++i)
printf("%d popped\n", pop(&list_a));
// test print copy list
printf("head copy:\n");
printList(&list_a_copy);
// test pop copy list
for (i = 0; i < 4; ++i)
printf("%d popped\n", pop(&list_a_copy));
}
The issue is with the way how double pointers are used.
Here is the full working code:
I have made some changes on the way how double pointers were used.
You can see the changes in pop function and copyList function.
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node* next;
};
static int length(struct node** head);
static void push(struct node** head, int data);
static int pop(struct node** head);
static void appendNode(struct node** head, int data);
static struct node *copyList(struct node** head);
static void printList(struct node** head);
/************************************************************
length - return length of a list
************************************************************/
int length(struct node** head) {
int count = 0;
struct node* current = NULL;
current = *head;
while (current != NULL) {
current = current->next;
++count;
}
return count;
}
/************************************************************
push - add new node at beginning of list
************************************************************/
void push(struct node** head, int data) {
struct node* new_ptr = NULL;
new_ptr = (struct node*)malloc(sizeof(struct node));
new_ptr->data = data;
new_ptr->next = *head;
*head = new_ptr;
}
/************************************************************
pop - delete node at beginning of non-empty list and return its data
************************************************************/
int pop(struct node** head) {
int val = 0;
struct node* temp = NULL;
if (*head != NULL) {
val = (*head)->data;
temp = (*head)->next;
free(*head);
*head = temp;
}
return(val);
}
/************************************************************
appendNode - add new node at end of list
************************************************************/
void appendNode(struct node** head, int data) {
struct node* current = NULL;
struct node* previous = NULL;
struct node* new_ptr = NULL;
current = *head;
previous = current;
while (current != NULL) {
previous = current;
current = current->next;
}
new_ptr = (struct node*)malloc(sizeof(struct node));
new_ptr->data = data;
new_ptr->next = NULL;
previous = new_ptr;
}
/************************************************************
copyList - return new copy of list
************************************************************/
struct node* copyList(struct node** head) {
struct node* copy = NULL;
struct node* current = NULL;
struct node* new_ptr = NULL;
/* Copy current head to copy */
current = *head;
while (current != NULL) {
appendNode(&copy, current->data);
current = current->next;
}
return copy;
}
/************************************************************
printList - print linked list as "List: < 2, 5, 6 >" (example)
************************************************************/
void printList(struct node** head) {
struct node* current = NULL;
printf("List: < ");
current = *head;
if (current == NULL)
printf("none ");
while (current != NULL) {
printf("%d", current->data);
current = current->next;
if (current != NULL)
printf(", ");
}
printf(" >\n");
}
void main() {
int i; // index used for loops
struct node *list_a; // a new list
struct node *list_a_copy; // copy of list
list_a = NULL; // initialize empty list
list_a_copy = NULL; // initialize empy list
// test push
for (i = 0; i < 4; ++i)
push(&list_a, i);
// test length
printf("Length of list = %d\n", length(&list_a));
// test print head list
printf("head:\n");
printList(&list_a);
// test append node
for (i = 4; i < 8; ++i)
appendNode(&list_a, i);
// test print head list
printf("head(append):\n");
printList(&list_a);
// make a copy of list
list_a_copy = copyList(&list_a);
// test pop head list
for (i = 0; i < 4; ++i)
printf("%d popped\n", pop(&list_a));
// test print copy list
printf("head copy:\n");
printList(&list_a_copy);
// test pop copy list
for (i = 0; i < 4; ++i)
printf("%d popped\n", pop(&list_a_copy));
}
From the error log, I notice that you have incompatible types multiples time. It would help if you post your main.cpp as well.
p.s Like Mike G said, double pointer is really excessive. You can implement a linked list using a single pointer.
Problem is in your pop() function...take a look.
you are assigning
val=head->data;
temp = head->next;
also you are freeing the head and then reassigning.
you should do like this
val=(*head)->data;
temp=(*head)->next;
and while freeing memory...free the temp and reassign head to its next.

C: How to free nodes in the linked list?

How will I free the nodes allocated in another function?
struct node {
int data;
struct node* next;
};
struct node* buildList()
{
struct node* head = NULL;
struct node* second = NULL;
struct node* third = NULL;
head = malloc(sizeof(struct node));
second = malloc(sizeof(struct node));
third = malloc(sizeof(struct node));
head->data = 1;
head->next = second;
second->data = 2;
second->next = third;
third->data = 3;
third->next = NULL;
return head;
}
I call the buildList function in the main()
int main()
{
struct node* h = buildList();
printf("The second element is %d\n", h->next->data);
return 0;
}
I want to free head, second and third variables.
Thanks.
Update:
int main()
{
struct node* h = buildList();
printf("The element is %d\n", h->next->data); //prints 2
//free(h->next->next);
//free(h->next);
free(h);
// struct node* h1 = buildList();
printf("The element is %d\n", h->next->data); //print 2 ?? why?
return 0;
}
Both prints 2. Shouldn't calling free(h) remove h. If so why is that h->next->data available, if h is free. Ofcourse the 'second' node is not freed. But since head is removed, it should be able to reference the next element. What's the mistake here?
An iterative function to free your list:
void freeList(struct node* head)
{
struct node* tmp;
while (head != NULL)
{
tmp = head;
head = head->next;
free(tmp);
}
}
What the function is doing is the follow:
check if head is NULL, if yes the list is empty and we just return
Save the head in a tmp variable, and make head point to the next node on your list (this is done in head = head->next
Now we can safely free(tmp) variable, and head just points to the rest of the list, go back to step 1
Simply by iterating over the list:
struct node *n = head;
while(n){
struct node *n1 = n;
n = n->next;
free(n1);
}
One function can do the job,
void free_list(node *pHead)
{
node *pNode = pHead, *pNext;
while (NULL != pNode)
{
pNext = pNode->next;
free(pNode);
pNode = pNext;
}
}
struct node{
int position;
char name[30];
struct node * next;
};
void free_list(node * list){
node* next_node;
printf("\n\n Freeing List: \n");
while(list != NULL)
{
next_node = list->next;
printf("clear mem for: %s",list->name);
free(list);
list = next_node;
printf("->");
}
}
You could always do it recursively like so:
void freeList(struct node* currentNode)
{
if(currentNode->next) freeList(currentNode->next);
free(currentNode);
}

Resources