-1

I have tried creating a program that uses simple stack functions like push to add the contents of the statement onto a stack from where I then print out each character and then reverse the statement. I have used the '.' and '->' member access variables to change the contents of the struct based stack. Upon compiling it prints out the original statement, but after that it gives a segmentation error, saying I am attempting to dereference an uninitialised pointer. Can someone guide me as to how I should solve this problem as it isn't stating the line I have made the problem either.

#include <stdio.h>
#define MAX 1000
#define FULL (MAX - 1)
#define EMPTY -1

typedef struct stack {char s[MAX]; int top;} stack;
int top = EMPTY;

int isFull()
{
  if(top == FULL)
    return 1;
  else
    return 0;
}


int isEmpty()
{
  if(top == EMPTY)
    return 1;
  else
    return 0;
}


void reset(stack *stk)
{
  stk -> top = EMPTY;
}


void push(char c, stack *stk)
{
  stk -> top++;
  (*stk).s[(*stk).top] = c;
}


char pop(stack *stk)
{
  return (*stk).s[(*stk).top--];
}


void print(stack *stk)
{
  int i;
  while(1)
  {
    if(isEmpty())
    {
      printf("Stack underflow\n");
      break;
    }
    for(i = 0; i <= top; i++)
    {
      printf("%c\n", (*stk).s[i]);
    }
    printf("\n");
    return;
  }
}


void reverse(stack *stk)
{
  int i;
  while(1)
  {
    if(isEmpty())
    {
      printf("Stack underflow\n");
      break;
    }
    for(i = top; i >= 0; i--)
    {
      printf("%c", (*stk).s[i]);
    }
    printf("\n");
    return;
  }
}

char peek(const stack *stk)
{
  while(1)
  {
    if(isEmpty())
    {
      printf("Stack underflow\n");
      break;
    }
    return (*stk).s[(*stk).top];
  }
}


int main()
{
  stack stack_of_char;
  char *str = "i am otto am i";
  int i;
  reset(&stack_of_char);
  printf("original is: %s\n", str);
  while(str[i] != '\0')
  {
    push(str[i++], &stack_of_char);
  }
  print(&stack_of_char);
  reverse(&stack_of_char);
  return 0;
}
starball
  • 20,030
  • 7
  • 43
  • 238
Ibs
  • 1
  • 2
  • Have you tried running your code line-by-line in a debugger while monitoring the values of all variables, in order to determine in which line your program stops behaving as intended? If you did not try this, then you may want to read this: [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/q/25385173/12149471) You may also want to read this: [How to debug small programs?](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) – Andreas Wenzel Jul 15 '22 at 00:45
  • 2
    Turn up the compiler warnings and pay attention to them. https://godbolt.org/z/7cdev9ovM – Retired Ninja Jul 15 '22 at 00:49
  • Side note: One would normally write `(*stk).s[(*stk).top] = c;` like this instead: `stk->s[stk->top] = c;` – Andreas Wenzel Jul 15 '22 at 00:52
  • @AndreasWenzel I did in fact try rewriting my entire code using pointer access operators for e.g. `stk->s[stk->top] = c;` but it still gave me a segmentation error. Also there aren't really variables I have to monitor rather just adding the characters to the stack and printing them backwards. The printing part is what isn't happening – Ibs Jul 15 '22 at 01:04
  • Why this -> `int top = EMPTY;`? Because of this `top` variable, you will get `Stack Underflow`. Instead, you should use the `top` of stack which is defined in `struct stack`. – H.S. Jul 15 '22 at 01:21
  • @H.S. it is related to the other functions. top needs to be a global variable, and empty to start with, so that push and all the other functions can work, doesn't it? – Ibs Jul 15 '22 at 01:28
  • @Ibs Where are you modifying the this global `int top = EMPTY;` in your code? In the operation like `push` and `pop` you are modifying `top` of `struct stack`. So, you should use `top` of `struct stack` everywhere. Pass pointer to `struct stack` in `isEmpty()` and `isFull()` and check the respective `top` of stack. – H.S. Jul 15 '22 at 01:31
  • @ibs No. Your `isEmpty` function _etc_ should take a stack parameter and you should not have a global `top` variable at all. The stack object itself is the one that maintains its own top value that is relative to the data it contains. – paddy Jul 15 '22 at 01:31
  • @paddy thank you for bringing this to my attention. I didn't realize that there is no need to declare a separate top variable. However, how am I supposed to initialise the value of top to EMPTY inside the struct then? – Ibs Jul 15 '22 at 01:52
  • You are already doing that in the `reset` function. That is essentially what initializes your struct. Please see my answer for a clean-up of your code, with fixes, and a bit of general explanation. – paddy Jul 15 '22 at 01:54

2 Answers2

1

There are several issues with your program. Let's begin with the global variable top. This is causing problems because on the one hand you have a stack struct responsible for maintaining a stack, and that has its own top. But then you have this global which you're not even using anywhere. It's almost like you added it to get around compiler errors that you didn't understand ;)

So let's ditch that, and fix your stack functions. I'm rearranging the parameters of the push function so that the stack is the first argument. This is a bit more conventional.

typedef struct stack {
    char s[MAX];
    int top;
} stack;

int isFull(stack *stk)
{
    return stk->top == FULL;
}

int isEmpty(stack *stk)
{
    return stk->top == EMPTY;
}

void reset(stack *stk)
{
    stk->top = EMPTY;
}

void push(stack *stk, char c)
{
    if (isFull(stk))
        return;
    stk->s[++stk->top] = c;
}

char pop(stack *stk)
{
    if (isEmpty(stk))
        return '\0';
    return stk->s[stk->top--];
}

For the pop function, I arbitrarily return a NUL character if the stack is empty, because something must be returned. But really, you should never call this function if the stack is empty.

Let's look at your display functions now. The first thing I notice is that these are really convoluted. There is no need for that complexity. Look here:

void print(stack *stk)
{
    for(int i = 0; i <= stk->top; i++)
    {
        printf("%c\n", stk->s[i]);
    }
    printf("\n");
}

void reverse(stack *stk)
{
    for(int i = stk->top; i >= 0; i--)
    {
        printf("%c", (*stk).s[i]);
    }
    printf("\n");
}

char peek(const stack *stk)
{
    if (isEmpty(stk))
    {
        printf("Stack empty!\n");
        return '\0';
    }
    return stk->s[stk->top];
}

And so all that remains is a little tidy-up of your main function, and adjust the parameter order for push.

int main()
{
    const char *str = "i am otto am i";
    printf("original is: %s\n", str);

    stack stack_of_char;
    reset(&stack_of_char);
    for (int i = 0; str[i]; i++)
    {
        push(&stack_of_char, str[i]);
    }

    print(&stack_of_char);
    reverse(&stack_of_char);
}

Note also that you shouldn't really be walking over your stack with those functions. The typical way you would use a stack to reverse something is to push values onto it and then pop them off. So, you can print the string in reverse like this:

    // Pop characters from stack to print in reverse
    while (!isEmpty(&stack_of_char))
    {
        char c = pop(&stack_of_char);
        putc(c, stdout);
    }
    putc('\n', stdout);
paddy
  • 60,864
  • 6
  • 61
  • 103
  • Thank you so much, this has clarified all of my confusions. Since I am new to C programming I haven't really learnt what formatting is more appealing, or how to make my code more simple. But your tips really helped! – Ibs Jul 15 '22 at 02:00
  • 1. Would it be better that `push` returns a boolean to indicate that it was successful. 2. With `pop` and indication to unable to do do, return an `int`. Why have `EMPTY` and `FULL` when -1 or zero/ MAX will do – Ed Heal Dec 28 '22 at 23:36
0

Without initialization, the integer will be a random value. It is the root cause of the memory access error.

You will need to initialize the variable properly. In main function, instead of

int i;,

you should use

int i = 0;.

Assume that you plan to access the value starting from index 0.

Seinlin
  • 79
  • 4
  • In main function, otherwise, `while(str[i] != '\0')` will start from an unknown index. – Seinlin Jul 15 '22 at 01:05
  • thank you, this solved the segmentation error problem but the print and reverse functions are printing "Stack Underflow" instead of the stack itself. Does this mean there is an error in the push function? – Ibs Jul 15 '22 at 01:18
  • Yes, this will solve the the segmentation fault error. I didn't have a chance to look at the other implementation. As the segmentation fault is gone, it should be easy to debug it. – Seinlin Jul 15 '22 at 01:23
  • 1
    @Seinlin With regards to your first comment, please [edit your answer](https://stackoverflow.com/posts/72988061/edit) instead of posting clarifications in the comments. A good answer should describe the fix, explain the cause of the issue and why the fix is valid. – paddy Jul 15 '22 at 01:25
  • For your reference. https://everythingcomputerscience.com/discrete_mathematics/Stacks_and_Queues.html – Seinlin Jul 15 '22 at 01:26