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

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

Related

How to Use Typedef Structure Name with Pointer

I am trying to implement a linked list using the given structure for a bigger project. The structure is defined below:
typedef struct node {
unint32_t size; // = size of the node
struct node * link; // = .next pointer
} * ListNode;
I was able to implement a linked list using struct node *. But when I attempt to use ListNode like in the following program:
typedef struct node {
unint32_t size;
struct node * link;
} * ListNode;
void insert_node (ListNode * head, unint32_t size) {
ListNode new_node = (ListNode) malloc (sizeof(ListNode));
new_node->size = size;
new_node->link = NULL;
if (head == NULL) {
head = &new_node;
}
else {
ListNode current = *head;
while (current->link != NULL) {
current = current->link;
}
current->link = new_node;
}
}
int main (int argc, char const * argv[]) {
ListNode head = NULL;
insert_node (&head, 10);
insert_node(&head, 20);
ListNode ptr = head;
while (ptr != NULL) {
printf ("%d ", ptr->size);
}
printf ("\n");
return 0;
}
I get a segmentation fault. Why is that? It even says that struct node * and ListNode are incompatible pointers/types. I thought they were the same struct just named differently.
A little clarification
typedef struct node {
unint32_t size;
struct node * link;
} *ListNode;
creates a type called ListNode. It is a pointer to a struct node. It is not a struct node
So when you do
sizeof(ListNode)
you get the size of a pointer, not the size of struct node
You needed to do
sizeof(struct node)
A very common thing to do is this
typedef struct node {
uint32_ size;
struct node* link;
} *PListNode, ListNode;
this creates 2 types
PlistNode which is a pointer to a struct node
ListNode which is a struct node
the 'P' is a reminder that this is a pointer
so now you can do
PListNode pn = malloc(sizeof(ListNode));
Since you supply a struct node** (a ListNode*) to insert_node, you need to dereference it to assign to it.
You malloc the size of a struct node* (a ListNode) but you need to malloc the size of a struct node.
You also need to do ptr = ptr->link in the loop in main.
Example:
void insert_node(ListNode* head, uint32_t size) {
// corrected malloc, you don't want the sizeof a pointer but the
// size of a `node`:
ListNode new_node = malloc(sizeof *new_node);
new_node->size = size;
new_node->link = NULL;
if (*head == NULL) { // corrected check (dereference head)
*head = new_node; // corrected assignment
} else {
ListNode current = *head;
while (current->link != NULL) {
current = current->link;
}
current->link = new_node;
}
}
int main() {
ListNode head = NULL;
insert_node(&head, 10);
insert_node(&head, 20);
// the below loop had no exit condition before:
for(ListNode ptr = head; ptr; ptr = ptr->link) {
printf("%d ", ptr->size);
}
printf("\n");
}
Demo

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 Programming

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.

trouble updating tail pointer in queue adt using singly linked list

i am trying to make a queue library that is based on a linked list library i already made. specifically i am having troubles updating the tail pointer in the queue structure after i add a new node to the linked list.
linked list structure:
struct listNode {
int nodeLength;
int nodeValue;
struct listNode *next;
};
typedef struct listNode node;
queue structure:
struct QueueRecord {
node *list;
node *front;
node *back;
int maxLen;
};
typedef struct QueueRecord queue;
so here is my add function in the queue library
void add(queue currentQueue, int data){
addTail(currentQueue.list, data, data+5);
currentQueue.back = currentQueue.back->next;
}
and the addTail function from the linked list library
void addTail (node *head, int value, int length) {
node *current = head;
node *newNode = (struct listNode *)malloc(sizeof(node));
newNode = initNode(value, length);
while (current->next != NULL)
current = current->next;
newNode->next = NULL;
current->next = newNode;
}
so again my problem is the tail pointer is not getting set to the last node in the list. it is remaining in the same place as the head pointer. ive been researching this for hours trying to see if im just missing something small but i cant find it. if more code or explanation is needed to understand my problem i can provide it.
how a queue is created:
queue createQueue(int maxLen){
queue newQueue;
newQueue.list = createList();
newQueue.front = newQueue.list;
newQueue.back = newQueue.list;
newQueue.maxLen = maxLen;
return newQueue;
}
node *createList (){
node *head = NULL;
head = (struct listNode *)malloc(sizeof(node));
head->next = NULL;
return head;
}
node *initNode (int value, int length){
node *newNode = NULL;
newNode = (struct listNode *)malloc(sizeof(node));
newNode->nodeValue = value;
newNode->nodeLength = length;
newNode->next = NULL;
return newNode;
}
void add(queue currentQueue, int data){
You are passing a copy of the queue struct to add, so only the copy's members are changed. You need to pass a queue* to the function to be able to change the members of the queue itself.
void add(queue *currentQueue, int data){
if (currentQueue == NULL) {
exit(EXIT_FAILURE);
}
addTail(currentQueue->list, data, data+5);
currentQueue->back = currentQueue->back->next;
}
and call it as add(&your_queue);
In your addTail function, you should check whether head is NULL too.
And with
node *newNode = (struct listNode *)malloc(sizeof(node));
newNode = initNode(value, length);
in addTail, you have a serious problem. With the assignment newNode = initNode(value, length);, you are losing the reference to the just malloced memory.
If initNode mallocs a new chunk of memory, it's "just" a memory leak, then you should remove the malloc in addTail.
Otherwise, I fear initNode returns the address of a local variable, à la
node * initNode(int val, int len) {
node new;
new.nodeValue = val;
new.nodeLength = len;
new.next = NULL;
return &new;
}
If initNode looks similar to that, that would cause a problem since the address becomes invalid as soon as the function returns. But your compiler should have warned you, if initNode looked like that.
Anyway, without seeing the code for initNode, I can't diagnose the cause.
But if you change your addTail to
void addTail (node *head, int value, int length) {
if (head == NULL) { // violation of contract, die loud
exit(EXIT_FAILURE);
}
node *current = head;
node *newNode = malloc(sizeof(node));
if (newNode == NULL) {
exit(EXIT_FAILURE); // or handle gracefully if possible
}
newNode->nodeValue = value;
newNode->nodeLength = length;
newNode->next = NULL;
while (current->next != NULL)
current = current->next;
current->next = newNode;
}
it should work.
However, since you have pointers to the first and the last node in the list, it would be more efficient to use the back pointer to append a new node,
void add(queue *currentQueue, int data){
node *newNode = malloc(sizeof *newNode);
if (newNode == NULL) {
exit(EXIT_FAILURE); // or handle gracefully if possible
}
newNode->nodeValue = data;
newNode->nodeLength = data+5;
newNode->next = NULL;
currentQueue->back->next = newNode;
currentQueue->back = newNode;
}
since you needn't traverse the entire list to find the end.
A simple sample programme
#include <stdlib.h>
#include <stdio.h>
struct listNode {
int nodeLength;
int nodeValue;
struct listNode *next;
};
typedef struct listNode node;
struct QueueRecord {
node *list;
node *front;
node *back;
int maxLen;
};
typedef struct QueueRecord queue;
node *createList (){
node *head = NULL;
head = (struct listNode *)malloc(sizeof(node));
head->next = NULL;
return head;
}
void addTail (node *head, int value, int length) {
if (head == NULL) { // violation of contract, die loud
exit(EXIT_FAILURE);
}
node *current = head;
node *newNode = malloc(sizeof(node));
if (newNode == NULL) {
exit(EXIT_FAILURE); // or handle gracefully if possible
}
newNode->nodeValue = value;
newNode->nodeLength = length;
newNode->next = NULL;
while (current->next != NULL)
current = current->next;
current->next = newNode;
}
queue createQueue(int maxLen){
queue newQueue;
newQueue.list = createList();
newQueue.front = newQueue.list;
newQueue.back = newQueue.list;
newQueue.maxLen = maxLen;
return newQueue;
}
void add(queue *currentQueue, int data){
if (currentQueue == NULL) {
exit(EXIT_FAILURE);
}
addTail(currentQueue->list, data, data+5);
currentQueue->back = currentQueue->back->next;
}
int main(void) {
queue myQ = createQueue(10);
for(int i = 1; i < 6; ++i) {
add(&myQ, i);
printf("list: %p\nfront: %p\nback: %p\n",
(void*)myQ.list, (void*)myQ.front, (void*)myQ.back);
}
node *curr = myQ.front->next;
while(curr) {
printf("Node %d %d, Back %d %d\n", curr->nodeValue,
curr->nodeLength, myQ.back->nodeValue, myQ.back->nodeLength);
curr = curr->next;
}
while(myQ.list) {
myQ.front = myQ.front->next;
free(myQ.list);
myQ.list = myQ.front;
}
return 0;
}
works as expected, also with the alternative add implementation.
i think you never initialized back, so back->next is some random pointer?

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