1

EDIT
Thank you everyone, I now understand that I was passing by value. But now I have another doubt regarding this.
Here, the append function's task involves changing the end pointer.
Both the arguments of append function are pointer's, in 1st case, 1st argument is &pt1 and 2nd argument is &pt2.
The function makes a copy of end pointer which has type of struct point. Since &pt1 is passed then this duplicate end pointer has x component as 1 and y component as -1 and next component as NULL. Now we change this copy's next component to newpt pointer and return the newpt pointer.

Back to the the main func, original end pointer now has the value of &pt2.
Acc to what I understood, end->next = newpt; shouldn't produce any change in the original end pointer in main.
So then why do I get a liked list. Here, is the code:

struct point{
    int x;
    int y;
    struct point *next;
};
void printPoints(struct point *);
void printPoint(struct point *);
struct point * append(struct point *, struct point *);
void main(){
    struct point pt1={1,-1,NULL};
    struct point pt2={2,-2,NULL};
    struct point pt3={3,-3,NULL};
    struct point *start, *end;
    start=end=&pt1;
    end=append(end,&pt2);
    end=append(end,&pt3);
    printPoints(start);
}
void printPoint(struct point *ptr){
    printf("(%d, %d)\n", ptr->x, ptr->y);
}
struct point * append(struct point *end, struct point *newpt){
    end->next=newpt;
    return newpt;
}
void printPoints(struct point *start){
    while(start!=NULL){
        printPoint(start);
        start=start->next;
    }
}

What I get:
(1, -1)
(2, -2)
(3, -3)

What I think I should get:
(1, -1)


Original Question
I have a simple program to insert elements at the end of the linked list using a function call.
My Code:
struct Date{
    int data;
    struct Date *next;
};
void print(struct Date *date_head);
void add(int date, struct Date *date_head);

int main(){
    struct Date *date_head=NULL;
    add(12,date_head);
    add(15,date_head);
}
void print(struct Date *date_head){
    struct Date *ptr=date_head;
    printf("Dates: ");
    while(ptr!=NULL){
        printf("%d ",ptr->data);
        ptr=ptr->next;
    }
    printf("\n");
}
void add(int date, struct Date *date_head){
    //newDate
    struct Date *newDate;
    newDate = (struct Date *)malloc(sizeof(struct Date));
    newDate->data=date;
    newDate->next=NULL;

    //inserting newDate at end
    struct Date *date_ptr;
    date_ptr=date_head;
    if (date_ptr==NULL) {date_head=newDate;}
    else{
        while(date_ptr->next!=NULL){
            date_ptr=date_ptr->next;
        }
        date_ptr->next=newDate;
    }
    print(date_head);
}

What I want:
Dates: 12
Dates: 12 15

What I get:
Dates: 12
Dates: 15

The struct becomes NULL outside the add function. Even when I am using pointers. Why? I dont know if I am making a beginner mistake.

  • 1
    Remember that arguments to functions are passed *by value*. That means the value used in the call will be copied into the functions argument variable. Modifying this copy doesn't change the original. So with an assignment like `date_head=newDate`, you only assign to the local argument variable, the variable or expression you used in the call will not change value. Please do some research about *emulating pass by reference in C*. Hint: It involves pointers, the pointer-to operator `&`, and the dereference operator `*`. – Some programmer dude Jan 26 '22 at 13:01
  • Also and somewhat off topic: the `add` function is very inefficient. Imagine your list contains 100000 elements, then for adding another element you have to go through all 100000 existing elements. Normally for a linked list you should also maintain the tail pointer (pointer to the last element). Then adding an element is instantaneous. – Jabberwocky Jan 26 '22 at 13:04
  • Also read this: https://stackoverflow.com/questions/766893/how-do-i-modify-a-pointer-that-has-been-passed-into-a-function-in-c – Jabberwocky Jan 26 '22 at 13:08

2 Answers2

1

It is better at least to swap the parameters of the function like

void add( struct Date *date_head, int date );

The function accepts the pointer to the head node declared in main by value. That is the function deals with a copy of the value of the pointer. Changing the copy within the function does reflect on the original pointer.

Also the memory allocation within the function can fail. You should report such a situation to the caller of the function.

So the function should return an integer saying whether the allocation of the new node was successful and it should accept the pointer to the head node by reference that is through a pointer to it.

Taking all this into account the function declaration and definition will look the following way.

int add( struct Date **date_head, int date )
{
    struct Date *newDate = malloc( sizeof( struct Date ) );
    int success = newDate != NULL;

    if ( success )
    {
        newDate->data = date;
        newDate->next = NULL;

        while ( *date_head != NULL ) date_head = &( *date_head )->next;

        *date_head = newDate;
    }

    return success;
}

Within main you should write

struct Date *date_head=NULL;
add( &date_head, 12 );
add( &date_head, 15 );

Also the parameter of the function should have the qualifier const because the list is not being changed within the function.

void print( const struct Date *date_head );

And if you want to append new node to the tail of the list then it is better to declare a twp-sided singly-linked list.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

you are passing the value of date_head pointer to the add function, so the add function will have another copy of that pointer, and even if you change the value of this pointer in the add function and set it to some address number, it will not affect the date_head that you created in the main, so it will be always null, what you can do is pass it by the address instead:

int main(){
    struct Date *date_head=NULL;
    add(12,&date_head);
    add(15,&date_head);
}

and edit the add function to be like this :

void add(int date, struct Date **date_head){
    //newDate
    struct Date *newDate;
    newDate = (struct Date *)malloc(sizeof(struct Date));
    newDate->data=date;
    newDate->next=NULL;

    //inserting newDate at end
    struct Date *date_ptr;
    date_ptr=*date_head;
    if (date_ptr==NULL) {*date_head= newDate;}
    else{
        while(date_ptr->next!=NULL){
            date_ptr=date_ptr->next;
        }
        date_ptr->next=newDate;
    }
    print(*date_head);
}