1

The struct problem.

I wrote a code implementing a stack. If I pass sqStack* sq to this function init_stack(), the code ended up with an error. As seen in the comment of the following code.
But then I found out if I pass sqStack &sq to init_stack() function, the code works.
Can anyone explain to me? Thanks!

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

#define init_size 10
#define increment 1

typedef struct sqStack
{
    int* top;
    int* base;
    int stack_size;
}sqStack;

int init_stack(sqStack* sq)
{
    if(sq->base==NULL)
    {
       sq->base = (int*)malloc(init_size*sizeof(int));
    }
    if(sq->base==NULL) exit(-1);
    sq->stack_size=init_size;
    sq->top=NULL;
    sq->top=sq->base;
    return 1;
}
int push(sqStack* sq, int e)
{
    if(sq==NULL) exit(-1);
    if(sq->top-sq->base==sq->stack_size)
    {
        int* q = (int*)realloc(sq->base,  
        (init_size+increment)*sizeof(int));
        if(q==NULL) exit(-1);
        sq->base=q;
        sq->stack_size += increment;
        sq->top=sq->base+sq->stack_size;

    }
    *sq->top++=e;//Thread 1: EXC_BAD_ACCESS  If I pass sqStack* sq to this function, error occurs. But if I pass sqStack &sq, the code works.


    return 1;
}

int pop(sqStack* sq,int*e)
{
    if(sq==NULL) exit(-1);  
    if(sq->base==sq->top)  exit(-1);   
    sq->top-=1;   
    *e=*sq->top;   
    return 1;    
}

int empty(sqStack* sq)
{
    if(sq->base==sq->top) return 1;
    else return 0;
}


int main()
{
    sqStack* sq;
    init_stack(sq);
    push(sq,1);
    int e=
    pop(sq,e);
    printf("%d\n",*e);
/* sqStack sq;
    init_stack(&sq);
    push(&sq,1);
    int e;
    pop(&sq,&e);
    printf("%d\n",e);*/
    return 0;
}

In either case, the output is 1.

3
  • 5
    In the main function you have the pointer sq, but where does it point? I recommend you change it to be not a pointer, and use the address-of operator & when a pointer to it is needed. Commented Jan 28, 2019 at 14:40
  • & basically means "pointer to". Commented Jan 28, 2019 at 14:41
  • This is a classic problem. Either return the allocated node or use a pointer to pointer. In C, you should pass a pointer to a X to a function where you want your X to be modified. In this case, since you want a pointer to be modified, you ought to pass a pointer to a pointer. Commented Jan 28, 2019 at 14:45

2 Answers 2

6

Here you dereference an uninitialized (dangling) pointer:

sqStack* sq;
init_stack(sq);

(in init_stack()):

if(sq->base==NULL)
   ...

which immediately leads to undefined behaviour.

Better do it this way:

sqStack sq;
init_stack(&sq);

Now you properly allocate space for sqStack on your process stack and pass a pointer to that space to init_stack(). Every time you want to pass a pointer to that structure (e.g. in pop and push) you have to use &sq now.

Alternatively, you can dynamically allocate memory for sqStack like this:

sqStack *sq = malloc(sizeof(sqStack));
init_stack(sq);

which also reserves memory (this time on the heap).

A third variant is to leave the allocation of the structure to the init_stack() function. In this case, you have to pass a double-pointer to init_stack, so the address can be written to it (error-checking to be added by yourself):

int init_stack(sqStack** _sq) {
    sqStack* sq;
    sq = *_sq = malloc(sizeof(sqStack));
    sq->base = malloc(init_size*sizeof(int));
    ...

and in your main:

sqStack *sq;
init_stack(&sq);
...
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks! And is sq->top=NULL; in init_stack() necessary in the code??
@Liu No, since you overwrite this in the next line sq->top = sq->base; you can omit that.
Thanks! I know my problem with my code now, but why I used the same way to create a sequence, and it worked out well, why??
If I dynamically allocate memory for sqStack sqStack *sq = malloc(sizeof(sqStack)); init_stack(sq); sq wasn't initialized and after passing it to push, the code crushed, how should I fix it??
@Liu You have to show the full code for that (i.e. edit your question and add it there)
|
2

Problem solution

The problem lies in the fact that you reserve memory for sq as a pointer. Why is this problematic?

Well, we only have space for an address to a sqStack. If we pass sq to init_stack(), we dereference sq. This leads to nothing, as we initialised it as a pointer, and thus, if we try to assign values to its fields, we don't have space for it!

How to solve the issue? Simply initialise sq as a sqStack instead of a pointer to it:

sqStack sq;
init_stack(&sq);  /* pass by reference here */
/* code continued */

Suggestion

Also, I think a better struct to use would be

typedef struct sqStack {
  int *elements;
  int top;
}

In this manner, you can use the top as a means to keep track of your stack's size, and simply store the elements in a specially allocated array. Pushing would then look like

void push(sqStack *sq, int element) {
  sq->top++;
  if (sq->top - 1 == 0) {
    /* we need to allocate space */
    sq->elements = malloc(sizeof(int));
  } else {
    /* we need to reallocate space */
    sq->elements = realloc(sq->elements, sq->top * sizeof(int));
  }
  sq->elements[sq->top - 1] = element;
}

...and revise the other functions in a similar way. But this is only a suggestion.

4 Comments

Thanks! And is sq->top=NULL; in init_stack() necessary in the code??
@Liu I've added a suggestion that indirectly addresses your question.
a suggestion ??
Thanks! I know my problem with my code now, but why I used the similar way to create a sequence, and it worked out well, why??

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.