1

So I'm trying to implement a linked list stack that takes in char arguments and adds them to the link list with it's ascii code as the value of the nodes.

I pass in my nstack pointer into my push function and re-assign it to new_node in order to create a new top, but my push function doesn't seem to be reassigning my nstack node - it just prints the originally initialized nstack value. Why isn't nstack being reassigned?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct list_node {
    int element;
    struct list_node * pnext;
};

void push(struct list_node *operators, int e);

int pop(struct list_node *operators);


int main(int argc, char *argv[]) {
    int newvalue = (int)argv[1][0];
    struct list_node * nstack = (struct list_node*)malloc(sizeof(struct list_node));

    nstack->element = newvalue;
    nstack->pnext = NULL;
    int i;  
        for (i = 2; i < argc; i++) {
            push(nstack, (int)argv[i][0]);
        }
    printf("top: %d\n", nstack->element);
}

void push(struct list_node *nstack, int e) {
    struct list_node * new_node = (struct list_node*)malloc(sizeof(struct list_node));
    new_node->pnext = nstack;
    new_node->element = e;
    nstack = new_node;
}
David Tao
  • 61
  • 1
  • 7
  • 1
    C11 draft standard n1570: *6.5.2.2 Function calls 4 An argument may be an expression of any complete object type. In preparing for the call to a function, the arguments are evaluated, and each parameter is assigned the value of the corresponding argument. 93) A function may change the values of its parameters, but these changes cannot affect the values of the arguments. On the other hand, it is possible to pass a pointer to an object, and the function may change the value of the object pointed to.* – EOF Oct 24 '16 at 20:47
  • `void push(struct list_node *nstack, int e)` could be `struct list_node *push(struct list_node *nstack, int e)` which returns a pointer to be assigned by the caller. So `return new_node;` – Weather Vane Oct 24 '16 at 20:50
  • 1
    Short version: `nstack = new_node;` in your push function is meaningless to the caller. All you're changing is a local variable, not the caller's pointer. Either utilize the otherwise-unused result of your function to return the new pointer value, or pass the caller's pointer by address (as a pointer-to-pointer) and modify it via de-reference. One of the *many* duplicates of this problem [can be found **here**](https://stackoverflow.com/questions/19280753/keep-segfaulting-when-trying-to-pass-struct-into-function). – WhozCraig Oct 24 '16 at 20:59

2 Answers2

2

Because you are passing a copy of pointer (by value). You need something like this (pointer to pointer):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct list_node {
    int element;
    struct list_node * pnext;
};

void push(struct list_node **operators, int e);

int pop(struct list_node *operators);


int main(int argc, char *argv[]) {
    //int newvalue = (int)argv[1][0];
    int newvalue = 1;
    struct list_node * nstack = (struct list_node*)malloc(sizeof(struct list_node));

    nstack->element = newvalue;
    nstack->pnext = NULL;

    int i;
        for (i = 2; i < 7; i++) {
            //push(nstack, (int)argv[i][0]);
            push(&nstack, i);
        }
    printf("top: %d\n", nstack->element);
}

void push(struct list_node **nstack, int e) {
    struct list_node * new_node = (struct list_node*)malloc(sizeof(struct list_node));
    new_node->pnext = *nstack;
    new_node->element = e;
    *nstack = new_node;
}
Tarod
  • 6,732
  • 5
  • 44
  • 50
1

To expand on Tarod's correct point. What the caller function is doing is taking a copy of your pointer value and putting it onto the stack or in a register (compiler dependent) that will then be used in your push function. However, within your push function you're actually changing the value in this register or stack location before returning. But when you return the caller function basically discards this information (its popped of the stack - or, again depending on the compiler, uses the register for something else). The only way around this is to pass the address of the pointer and deference this when you need to write to it as Tarod has shown.

cdcdcd
  • 547
  • 1
  • 5
  • 15