-1

Below code gives me an error Segmentation fault (core dumped) but if I uncomment return ptr and comment return &newStack it will work fine. Why this make difference, if we consider pass by reference in function then it can take function(&variable), here we don't need to pass a pointer. I am a little confused about this concept.

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct
    {
        int top;
        char arr[10];
    }Stack;
    
    Stack * create_stack(){
        Stack newStack,*ptr;
        newStack.top = -1;
        ptr = &newStack;
        
        //return ptr; 
        return &newStack;
    }
    
    int main(){
        Stack * S1;
        S1 = create_stack();
        printf("%d\n",S1->top);
        return 0;
    }
Karm Patel
  • 174
  • 1
  • 7
  • 1
    *if we consider pass by reference* C doesn't pass anything "by reference". C only passes by value. The unary `&` operator is the "address of" operator - it does not denote a reference. A pointer is a variable that holds an address. – Andrew Henle Aug 24 '20 at 10:03
  • 1
    "it will work fine" - No, it won't, because in both cases you return a pointer to a local variable, which is undefined behaviour. Why might it differ with some seemingly irrelevant code changes on some compiler? Because it's undefined behaviour. So don't do it. (A practical explanation might be that your compiler's implementation of diagnostics is not fussy enough that it catches both variants of the same ill-formed code, but it's ill-formed in either case.) – underscore_d Aug 24 '20 at 10:04
  • The first instance of _undefined behavior_ occurs at the expression `S1 = create_stack();` in `main()`, where `create_stack()` is returning an _indeterminate value_ (the address of a local variable in this case) that is being assigned to a variable. It's fun to note that the _initialization_ `Stack * S1 = create_stack();` is _not_ undefined behavior (because objects are allowed to be initialized with indeterminate values, including _trap representations_), but any subsequent use of the value in `S1` would be undefined behavior. – Ian Abbott Aug 24 '20 at 10:59

2 Answers2

1

Why this make difference

Because that's the way undefined behavior work. Basically anything may happen, including the program appearing to work fine.

Returning pointers to local variables is undefined behavior. If you declare newStack as static, the code is valid, but you should have a very good reason for returning a pointer to a local stack variable. In most cases it's a sign of bad design.

returning a local variable from function in C

Undefined, unspecified and implementation-defined behavior

I'd use one of these options:

Stack * create_stack(){
    Stack *stack = malloc(sizeof *stack);
    // Outside the scope of the question, but error checking malloc
    // is a good habit
    if(stack)
        stack->top = -1;

    return stack;
}

int main(void)
{
    Stack *stack = create_stack();
    // Do work
    free(stack);
}

and

void create_stack(Stack *stack){
    stack->top = -1;
}

int main(void)
{
    Stack stack;
    create_stack(&stack);
    // Do work
    // No free required
}

Depending on whether you want to use dynamic allocation or not.

Example with static, WHICH YOU SHOULD NOT DO!

Stack * create_stack(){
    static Stack stack;
    stack.top = -1;
    return &stack;  // Valid, but very bad as seen below
}

int main(void)
{
    Stack *stack1 = create_stack();
    Stack *stack2 = create_stack();

    // Now stack1 and stack2 will point to THE SAME stack
}

The above code is valid, but it will probably not do what you want. If you use static, you cannot create two different stacks.

klutt
  • 30,332
  • 17
  • 55
  • 95
-1

The address space of newStackis not valid anymore when the function returns. You could do:

    Stack * create_stack(){
        Stack *ptr;
        static Stack newStack;
        newStack.top = -1;
        ptr = &newStack;
        
        //return ptr; 
        return &newStack;
    }
stderr
  • 143
  • 5
  • 2
    They _could_, but they shouldn't... because that function is named as if it will create a new `Stack` every time, but now you made it only store one shared stack per process and always return that. What they probably want is to dynamically allocate a new one with every call. But in fact the question seems to be not '(why) is this invalid' but rather 'why is this only diagnosed as invalid when written in a certain way'. – underscore_d Aug 24 '20 at 10:05
  • @underscore_d Good point. I just thought it would be easier to understand. – stderr Aug 24 '20 at 10:10
  • @stderr It's not wrong to explain why things you should not do is valid code, but if you do, you must also explain that you should not do like that. – klutt Aug 24 '20 at 10:16
  • @klutt You're right. It was a bad way to explain this problem. – stderr Aug 24 '20 at 10:22