Double pointer in linked list - c

I almost figured out this code, but there are two details I can't figure out.
I found this code on YouTube.
source: https://www.youtube.com/watch?v=VOpjAHCee7c
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int vaule;
struct node *next;
}node_t;
void printlist(node_t *head)
{
node_t *temp = head;
while(temp != NULL)
{
printf("%d - ", temp->vaule);
temp = temp->next;
}
printf("\n");
}
node_t *create_node(int var)
{
node_t *res = malloc(sizeof(node_t));
res->vaule = var;
res->next = NULL;
return res;
}
node_t *insert_at_head(node_t **head, node_t *node_to_insert)
{
node_to_insert->next = *head;
*head = node_to_insert;
return node_to_insert;
}
void find_node()
int main()
{
node_t *tmp;
node_t *head = NULL;
for(int i = 0; i < 15; i++)
{
tmp = create_node(i);
head = insert_at_head(&head, tmp);
}
printlist(head);
return 0;
}
1) Why do we use the nested struct?
typedef struct node{
int vaule;
struct node *next;
}node_t;
I know about nested structures but I didn't understand why we use it here.
2) Why do we use double pointer?
node_t *insert_at_head(node_t **head, node_t *node_to_insert)
{
node_to_insert->next = *head;
*head = node_to_insert;
return node_to_insert;
}
if I change this code like this:
node_t *insert_at_head(node_t *head, node_t *node_to_insert)
{
node_to_insert->next = head;
return node_to_insert;
}
then nothing will change

Why do we use the nested struct?It's not a nested struct. struct node *next is a pointer, and as its name indidcates, it points to the next element.
Why do we use double pointer? Read this: How do I modify a pointer that has been passed into a function in C?

1)Why do we use the nested struct?
It is not a nested struct, but a linked list. Each node has a pointer to the next node (or to NULL for the last node of a list
2)Why do we use double pointer?
C only passes parameters by value. The idiomatic ways to change a variable from the caller are:
assign the return value to that variable. It is the best way, but you can only return one single value that way
pass a pointer to the variable and use the pointer to change the value. As we want to change the value of head which is already a pointer, we have to pass a pointer to pointer.
Here the write of the code has decided to change the passed header to clearly show that it is an input/output parameter, and also returns it because it had no better value to return.

Related

Can I use a CreatNode function to return a struct rather than its steps repeated in All other functions?

I want to make a CreatNode() function in C to be called by other functions. I am playing around with code trying to reach great readability and functionality. The professor has a CreatEmptyList() function but not a CreatNode().She is negligent and not the capable of the concepts and C lagnguage and didn't give me an answer.
I don't need this exploration and trying ideas that come to my mind to pass the course, but my aim is to become a Dev not to graduate.
This is the code of the Prof:
typedef struct nodetype
{
int info;
struct nodetype *next;
} node;
node *head;
void createemptylist(node *head)
{
head=NULL;
}
void insertatbeginning(node *head, int item)
{
node *newNode;
/* allocate memory for the new node and initialize the data in it*/
newNode= malloc(sizeof(node));
newNode->info=item;
/* assign the value of head to the “next” of newNode*/
newNode->next=head;
/* assign the address of newNode to head */
head=newNode;
}
void insertatend(node *head, int item)
{
node *newNode;
newNode=malloc(sizeof(node));
newNode->info=item;
newNode->next=NULL;
if(head==NULL)
head=newNode;
else
{
node *prev=head;
while(prev->next!=NULL)
prev=prev->next;
prev->next=newNode;
}
}
All are the snippets from the PDF she provided not exactly a compilable code.
This is the code I am working on and it keeps giving errors:
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int info;
struct Node *Next;
}ListNode;
ListNode CreatNode(ListNode *Head){///These steps not to be repeated using this function
printf("\n=================\nEntered CreatNode Function");
ListNode *NewNode;
NewNode = malloc(sizeof(ListNode));
return *NewNode;
}
void CreatList(ListNode *Head){
printf("\n=================\nEntered CreatList Function");
Head = NULL;
}
void InserBeg(ListNode *Head, int item){
///CreatNode() steps here
NewNode=CreatNode(&Head);
NewNode->info = item; ///Inesrt value
NewNode->Next = Head;///Insert Adress inside Head to the Next point
Head = NewNode;
printf("\nFinished InsertBeg Function");
printf("\nValue inserted is: %d\n=================\n", NewNode->info);
}
void Append(ListNode *Head, int item){
///CreatNode() steps here
///NewNode=CreatNode(Head);
NewNode ->info = item;
NewNode ->Next = NULL;
if (Head==NULL){
Head=ListNode
}
else{
ListNode *Prev=Head;
while(while->Prev!=NULL){
Prev = Prev->Next;
}
Prev->Next=NewNode;
}
}
int main(){
ListNode *Head;
CreatList(&Head);
InserBeg(&Head, 8);
return 0;
}
errors:
C:\Users\User\Desktop\all\C\Single Linked List test.c|27|error: incompatible types when assigning to type 'ListNode * {aka struct Node *}' from type 'ListNode {aka struct Node}'|
Undeclared NewNode struct errors since it can't see it
Any help on coding my idea in different ways or make my code work?
The provided by the professor code is very bad.
For starters she uses a global variable head. As the variable is declared in the file scope then it is already initialized as a null pointer. So this function
void createemptylist(node *head)
{
head=NULL;
}
does not make a great sense. And moreover it does nothing with the original pointer head because it accepts its argument by value. That is it deals with a copy of the value of the original pointer.
By this reason other functions insertatbeginning and insertatend are wrong because they do not change the original pointer head that they accept by value.
void insertatbeginning(node *head, int item)
{
//...
head=newNode;
}
void insertatend(node *head, int item)
{
//...
head=newNode;
//...
}
They change a copy of the value of the original pointer.
The same problem is present in your functions.
As for the function CreatNode then as is it does not make a sense.
ListNode CreatNode(ListNode *Head){///These steps not to be repeated using this function
printf("\n=================\nEntered CreatNode Function");
ListNode *NewNode;
NewNode = malloc(sizeof(ListNode));
return *NewNode;
}
For starters the parameter head is not used within the function. You need to pass an integer argument to the function that will be used as an initializer for the data member info.
Instead of an object of the type ListNode you should return a pointer to the dynamically allocated object. Otherwise the function returns a copy of the dynamically allocated object and as a result the function will produce a memory leak.
Within the functions InserBeg and Append the name NewNode is undefined as for example
void InserBeg(ListNode *Head, int item){
///CreatNode() steps here
NewNode=CreatNode(&Head);
//...
And you are calling the functions passing expressions of incompatible pointer type ListNode ** instead of ListNode *.
CreatList(&Head);
InserBeg(&Head, 8);
Here is a demonstration program that shows how the function CreateNode and for example InsertBeg can be defined.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int info;
struct Node *next;
} ListNode;
ListNode * CreateNode( int info )
{
ListNode *new_node = malloc( sizeof( *new_node ) );
if ( new_node != NULL )
{
new_node->info = info;
new_node->next = NULL;
}
return new_node;
}
int InsertBeg( ListNode **head, int info )
{
ListNode *new_node = CreateNode( info );
int success = new_node != NULL;
if ( success )
{
new_node->next = *head;
*head = new_node;
}
return success;
}
int main( void )
{
ListNode *head = NULL;
if ( InsertBeg( &head, 10 ) )
{
puts( "New node is added." );
}
else
{
puts( "Error: not enough memory." );
}
}
The program output is
New node is added.

C: error: request for member 'next' in something not a structure or union OR error: '*list' is a pointer; did you mean to use '->'?

For my linked list, I have the following:
typedef struct node {
char * value;
struct node *next;
} NODE;
void delete_nth(NODE **list, int n){
NODE *cur = *list;
int i;
if (n == 0){
printf("\n==========\n");
list = list->next;
cur->next = NULL;
free(cur);
} else {
for(i = 0; i < n; i++){
cur = cur->next;
}
}
return ;
}
But it returns these errors:
error: '*list' is a pointer; did you mean to use '->'?
error: request for member 'next' in something not a structure or union
What am I doing wrong here?
The problem is NODE **. NODE ** becomes struct node ** which means pointer to pointer to struct node.
The following two lines from your program are not correct:
void delete_nth(NODE **list, int n){
NODE *cur = *list;
These lines should be changed to:
void delete_nth(NODE *list, int n){
NODE *cur = list;
So, now NODE **list is changed to NODE *list and NODE *cur = *list is changed to NODE *cur = list.
This line is not correct:
list = list->next;
list does not point to a struct but to a pointer to struct.
Also you don't want to update list but where list points to.
This would be
*list = (*list)->next;
If you change list, the calling function would not see it as it is only a copy of the passed value.
Besides this, you forgot to actually remove the nth element after iterating through your list. But that is another topic...

Building a Linked List of Strings

I had a singly linked list that took in integers successfully, but now I want to use strings. However it is not working. I am getting so many different errors about "casting". I am finding conflicting information online as well. One comment here, Creating linked list of strings, said not to use strcpy, but I see strcpy used in a few examples online.
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
struct node {
char value[];
struct node* next; // pointer of structure type
};
// set existing type, node, to the alias, node_t
typedef struct node node_t;
node_t *create_new_node(char value) {
// create space for node with malloc
node_t *result = malloc(sizeof(node_t));
// set the value of the new node
result->value = value;
//strcpy(result->value, value);
// set the value's next pointer to null
result->next = NULL;
return result;
}
node_t *insert_at_head(node_t **head, node_t *node_to_insert) {
node_to_insert->next = *head;
*head = node_to_insert;
return node_to_insert;
}
//Prints linked list
void printlist(node_t* head) {
node_t *temporary = head;
while (temporary != NULL) {
//print out the value of the node that temporary points to
// printf("%d - ", temporary->value);
// to move along the list
temporary = temporary->next;
}
printf("\n");
}
int main() {
node_t *tmp;
// declaring head pointer
node_t *head = NULL;
// CREATING LINKED LIST
// for (int i = 0; i < 25; i++) {
// tmp = create_new_node(i);
// // sending the address of the head variable
// //calling by reference
// //SINCE HEAD IS ALREADY A NODE POINTER
// insert_at_head(&head, tmp);
// }
printlist(head);
tmp = create_new_node("I like food");
insert_at_head(&head, tmp);
}
How can I get this Linked List of string to work?
Thank you.
If you reorganize it a bit, you will be able to allocate the space the struct & the place for the string in the single malloc.
struct node
{
struct node* next; // pointer of structure type
char value[];
};
// set existing type, node, to the alias, node_t
typedef struct node node_t;
node_t *create_new_node(const char *value)
{
// create space for node with malloc
node_t *result = malloc(sizeof(*result) + strlen(value) + 1);
if(result)
{
strcpy(result->value, value);
result->next = NULL;
}
return result;
}
Please use your compiler! I ran $gcc -Wall a.c on this code and got:
a.c:7:10: error: flexible array member not at end of struct
char value[];
^
a.c: In function ‘main’:
a.c:67:5: warning: passing argument 1 of ‘create_new_node’ makes integer from pointer without a cast [enabled by default]
tmp = create_new_node("I like food");
^
a.c:15:9: note: expected ‘char’ but argument is of type ‘char *’
node_t *create_new_node(char value) {
^
a.c:70:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
Now we know what the problems are. Firstly, char value[] should be char *value since it's a pointer rather than a flexible array member (FAM). You could also move the FAM to the end of the struct if you want as shown here.
Next, node_t *create_new_node(char value) is relying on a char value when you really want a string, char *value for the parameter. There are issues beyond this: you'll likely want to make a copy of the string for the node in case it disappears from the stack. This memory should be cleaned up after use.
Other tips:
Avoid noisy, redundant comments like:
// declaring head pointer
node_t *head = NULL;
malloc(sizeof(*name_of_the_var)); is safer than malloc(sizeof(node_t)); if the data changes.
node_t *insert_at_head(node_t **head, node_t *node_to_insert) modifying its parameter and returning it is a little unusual. I'd make it void to make the in-place contract explicit.
Alphabetize and remove unused imports.
Check that malloc calls succeeded.
Remember to return 0; from main.
typedef struct node node_t; is okay but also hides info--I prefer keeping the struct there.
Here's a possible rewrite:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char *value;
struct node* next;
};
struct node *create_new_node(char *value) {
struct node *node = malloc(sizeof(*node));
if (!node) {
fprintf(stderr, "%s:%d malloc failed\n", __FILE__, __LINE__);
exit(1);
}
node->next = NULL;
node->value = strdup(value);
if (!node->value) {
fprintf(stderr, "%s:%d malloc failed\n", __FILE__, __LINE__);
exit(1);
}
return node;
}
void insert_at_head(struct node **head, struct node *node_to_insert) {
node_to_insert->next = *head;
*head = node_to_insert;
}
void print_list(struct node *head) {
for (; head; head = head->next) {
printf("%s->", head->value);
}
puts("");
}
void free_list(struct node *head) {
while (head) {
struct node *tmp = head;
head = head->next;
free(tmp->value);
free(tmp);
}
}
int main() {
struct node *head = NULL;
for (int i = 0; i < 10; i++) {
char n[16];
sprintf(n, "%d", i);
insert_at_head(&head, create_new_node(n));
}
print_list(head);
free_list(head);
return 0;
}
Output:
9->8->7->6->5->4->3->2->1->0->

can't use a function with a 'pointer to pointer' input in another function. In C language

this code supposed to print : 'tree two one'
but it doesn't work. (the new_nod isn't added to the front of mylist)
anybody knows why? (actually in this code i wanted to use a function with a pointer to pointer input in another function but it didn't work(no changes applied to the mylist).
but it works when i'm using add_front function straightly in main.
#include <stdio.h>
#include <stdlib.h>
struct node{
char *word;
struct node *next;
};
struct node* create_node(char *str){
struct node *s;
s = (struct node *)malloc(sizeof(struct node));
if(s==NULL){
printf("couldn't malloc :(\n");
exit(-1);
}
s->word = str;
s->next = NULL;
return s;
}
void print_node(struct node *list){
struct node *current;
for(current = list; current !=NULL; current = current->next)
printf("%s ", current->word);
}
void add_front(struct node **list, struct node *new_node){
new_node->next= *list;
*list = new_node;}
void func(struct node*list, struct node*new_node){
add_front(&list, new_node);
}
int main()
{
struct node* mylist = create_node("one");
mylist->next = create_node("two");
struct node *new_node = create_node("tree");
func(mylist, new_node);
print_node(mylist);
}
Your add_front accepts a pointer to a pointer and other than missing a check for NULL is pretty much okay. But let's take a look at this:
void func(struct node*list, struct node*new_node){
add_front(&list, new_node);
}
What is add_front modifying here? The local pointer list. Which is just a copy of mylist in main.
So you haven't changed what mylist is pointing to.

Passing typedef structure as call by reference in C

I am trying to create a linked list in C and my code is as below.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
}node_t;
void insert_into_list(node_t *,int);
void print_list(node_t *);
node_t *create_node(int );
void insert_into_list(node_t *head, int value){
node_t *temp ;
temp = create_node(value);
if(head == NULL){
printf("Inserting node for the first time\n");
head = temp;
}else {
head->next = temp;
}
}
void print_list(node_t *head){
node_t *current = head;
while(current!=NULL){
printf("%d----->",current->data);
current = current->next;
}
printf("NULL");
}
node_t *create_node(int value){
node_t *new_node = malloc(sizeof(node_t));
if(new_node==NULL){
printf("Memory allocation failed for the list creation. :(");
return NULL;
}
new_node->data = value;
new_node->next = NULL;
return new_node;
}
int main(int argc, char *argv[]) {
node_t *head = NULL;
insert_into_list(head,10);
if(head==NULL){
printf("Still head is NULL :(");
}else{
printf("Head is not NULL:)");
}
print_list(head);
return 0;
}
In main, I am calling insert_into_list and even after successful memory allocation, i am not able to get the head value with the newly created node. Still showing the value as NULL.
I have debugged with gdb and found that upto below code, head is not NULL
printf("Inserting node for the first time\n");
head = temp;
I thought I am passing by reference and expected the value to get reflected in the caller function.
Please correct me.
If you want to pass by reference (or rather, the equivalent) in C you must pass a pointer. To pass a pointer by reference you have to pass a pointer to the pointer.
So in e.g. insert_into_list you must declare head as a pointer to a pointer:
void insert_into_list(node_t **head, int value)
And use the dereference operator when accessing the head variable.
You call it using the address-of operator &:
node_t *head = NULL;
insert_into_list(&head,10);

Resources