Passing typedef structure as call by reference in C - 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);

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.

Double pointer in linked list

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.

Practicing linked lists

So we learned about lists in class lately and I wanted to practice them. The program doesn't run. Did I fail in filling the nodes? I'm too dizzy to focus on finding the missing key. Sorry for posting such triviality!
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int val;
struct node *next;
}node_t;
node_t* create_node(int value,node_t *nextnode) {
node_t *newnode=(node_t*)malloc(sizeof(node_t));
if(newnode==NULL) {
printf("ERROR ALLOCATING");
exit(0);
}
newnode->val=value;
newnode->next=nextnode;
return newnode;
}
void fill_list(node_t *head) {
int i=1;
node_t *current;
for(;i<21;i++) {
current=create_node(i,head);
head=current;
}
}
void print_list(node_t *head) {
node_t *current=head;
while(current) {
printf("%d",current->val);
current=current->next;
}
}
int main() {
node_t *head=NULL;
fill_list(head);
print_list(head);
return 0;
}
Your problem is that fill_list never returns the new head. Thus, head in main remains NULL.
An easy way of changing that behaviour would be to have fill_list return the new head:
node_t* fill_list(node_t *head) {
int i=1;
node_t *current;
for(;i<21;i++) {
current=create_node(i,head);
head=current;
}
return head;
}
Within the function fill_list the parameter head is being changed.
void fill_list(node_t *head) {
int i=1;
node_t *current;
for(;i<21;i++) {
current=create_node(i,head);
head=current;
}
}
But the function deals with a copy of the argument passed to the function. So the original pointer head defined in main knows nothing about these changes.
You have to return the value of the parameter head of the function from the function and assign it to the pointer head defined in main.
So the function can look like
node_t * fill_list(node_t *head) {
for( int i = 1; i < 21; i++ )
{
head = create_node( i, head );
}
return head;
}
and in main there must be
node_t *head = NULL;
head = fill_list( head );
Another way is to pass the pointer head to the function fill_list by reference. In this case the function can look
void fill_list( node_t **head ) {
for ( int i = 1; i < 21; i++ ) {
*head = create_node( i, *head );
}
}
And in main you should write
node_t *head = NULL;
fill_list( &head );
Problem
Function arguments in C are 'pass-by-value'. The problem with this is that your fill_list function takes a pointer to a node_t called head, but any changes you make to this pointer, will not affect the value of head outside the function. head inside the function is a completely different thing to the head in your main().
Quick Fix
If you really want to change the value of head (the one outside the function) then you have to pass the function a pointer to the bit of memory in which head resides. For your example, this means a pointer to a pointer to a node_t.
So your fill_list would look like:
void fill_list(node_t **head) {
int i=1;
node_t *current;
for(;i<21;i++) {
current=create_node(i, *head);
*head=current;
}
}
Note that you must now dereference the pointer before passing it to create_node.
By dereferencing in the assignment *head = current, you are setting the contents of the memory pointed to by head. Which is the same memory holding the head variable declared in your main(). This is what you want.
Now you can call fill_list like this:
fill_list(&head)
Better Fix
Have fill_list return a pointer to the head, such as:
node_t* fill_list() {
int i=1;
node_t *head = NULL;
node_t *current;
for(;i<21;i++) {
current=create_node(i, head);
head=current;
}
return head;
}
and then main():
int main() {
node_t *head = fill_list();
print_list(head);
return 0;
}

How to change null pointer (of struct return type) to declared struct?

I am new to C programming. I am trying to implement Linked list by myself. I am encountering problem with pointers
I have function
void Insert(Node* head, int x)
to insert node at the beginning of Linked list. The problem is that when I insert the very first node and Node *head is NULL, the function Insert is not able to change the pointer address of null pointer to the newly created node. It seems as if the Node *head is passed by value and not by reference.
Code is provided below. In order to debug how address is changed throughout the execution, I used printf function.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *next;
} Node;
int main() {
Node *head = (Node*) malloc(sizeof(Node));
head = NULL;
printf("head in main(): %d\n", head); // For example: 100
Insert(head, 25);
return 0;
}
void Insert(Node *head, int x) {
Node *temp = (Node*) malloc(sizeof(Node));
temp->data = x;
temp->next = head;
printf("temp->next address: %d\n", temp->next); // also 100
head = temp;
printf("%d\n", head); // not 100, something else i.e 200
}
It seems as if the Node *head is passed by value and not by reference.
That is exactly right -- in C every parameter is always passed by value. The pointer is a value, and that value is passed by value, and the call
Insert(head, 25);
can never change the value of the variable named head. It reads the value of the variable (this value is a null pointer), gives that value to the function and never touches the variable head again no matter what the function does.
(Note that in your program you have two variables that are both named head -- one in main() and the other in Insert(). The variable in Insert() silently disappears when the function returns; nothing will automatically try to copy its value to the similarly-named variable in main()).
If you want to (conceptually) pass head by reference, you need to actually pass a pointer to it -- that is, in this case, a pointer to a pointer! You'd need to declare your function as
void Insert(Node **head, int x) { ... }
and call it as
Insert(&head, 25);
Then the actual parameter is a pointer to the variable head which gives the function a chance to update that variable, if you deference the parameter where appropriate:
// ...
temp->next = *head;
// ...
*head = temp;
// ...
Pass a pointer to a pointer to head. That way, you can set head to null.
void Insert(Node **head, int x) {
...
if (*head == NULL) {
*head = temp;
}
else {
...
*head->next = temp;
}
}
Usage:
Node *head = NULL;
Insert(&head, 10);
Having three answers suggesting the same I would like to offer an alternative:
Instead of passing a Node ** to Insert() you could instead have it return the new head, thus:
Node *Insert( Node *head, int x )
{
... your code ...
return head;
}
and if you call it by
head = Insert( head, 24 );
That is neither better nor worse then the other solution so you my do whatever you prefer
There are number of issues here.
1. Your printf statements need to be corrected.
2. To insert function you can pass double pointer.
3. Inside main function, you need not to do Node *head = (Node*) malloc(sizeof(Node));
I have modified your code as shown below. You can try running it and co-relate above points.
typedef struct Node {
int data;
struct Node *next;
} Node;
void Insert(Node **head, int x);
void Insert(Node **head, int x) {
Node *temp = (Node*) malloc(sizeof(Node));
temp->data = x;
temp->next = *head;
printf("temp->next address: %d\n", temp->data); // also 100
*head = temp;
printf("%d\n", (*head)->data); // not 100, something else i.e 200
}
int main() {
Node *head = NULL;
head = NULL;
Insert(&head, 25);
printf("head in main(): %d\n", head->data); // For example: 100
return 0;
}

linked list of strings in C

I am trying to create a linked list of strings in C and have had problems adding the first Node into the list. For whatever reason my program prints NULL even though I reference the head variable to newNode but it does not copy the string from struct pointer to struct pointer. Any help is appreciated. Thanks!
#include "stdafx.h"
#include <stdlib.h>
#include <string.h>
typedef struct stringData {
char *s;
struct stringData *next;
} Node;
Node *createNode(char *s) {
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->s = s;
newNode->next = NULL;
return newNode;
}
void insert(Node *head, Node *newNode) {
if (head == NULL) {
head->s = newNode->s;
head = newNode;
}
}
void printList(Node *head) {
while (head != NULL) {
printf("%s\n", head->s);
head = head->next;
}
}
int main()
{
Node *head = createNode(NULL);
Node *a = createNode("A");
insert(head, a);
printList(head);
return 0;
}
Following code snippet is wrong:
void insert(Node *head, Node *newNode) {...}
...
insert(head, a);
You need to pass the pointer by reference. Currently you are changing local copy (argument).
Fix
Change your insert as:
void insert(Node **head, Node *newNode) {...}
And call as:
insert(&head, a);
What elseAtleast insert (and possibly) more functions are not fool-proof (guaranteed null pointer dereference, else case not handled etc). You need to debug and fix many such cases. Working your approach properly on paper before coding may help.
Here is a modified version of the code that gives an example of inserting new nodes at both the start of a list and the end of a list. In fact, the insert function could be used to insert a new node at any position in the list, since all it needs is a pointer to a link and a pointer to the node to be inserted.
#include <stdlib.h>
#include <stdio.h>
typedef struct stringData {
char *s;
struct stringData *next;
} Node;
Node *createNode(char *s) {
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->s = s;
newNode->next = NULL;
return newNode;
}
void insert(Node **link, Node *newNode) {
newNode->next = *link;
*link = newNode;
}
void printList(Node *head) {
while (head != NULL) {
printf("%s\n", head->s);
head = head->next;
}
}
int main(void)
{
Node *head = NULL;
Node *tail = NULL;
Node *n;
n = createNode("B");
// First node at start of list - head is updated.
insert(&head, n);
// First node is also the tail.
tail = n;
n = createNode("A");
// Insert node at start of list - head is updated.
insert(&head, n);
n = createNode("C");
// Insert node at end of list.
insert(&tail->next, n);
// Update tail.
tail = n;
printList(head);
return 0;
}

Resources