-8

I tried to make a stack push pop operations with storing values from pop in an array. I have a few questions for this code.
1. Does the initialization part work well? When compiling, it seems there is no problem but I'm still curious.
2. Does the deletion part also work well? Although, I typed !, it seems it doesn't goes to else if(strcmp (str[i], "!")==0) part. 3. How could store values after pop operations? I want to store it as an array format but when I print out after storing them in the array, runtime error occured.
Here's the code:

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

typedef struct stack *Stack;

struct stack {
    char *array;
    int size;
    int top;
};//making stack


Stack create(int c);
Stack makeEmpty(void);//initialization
int isEmpty(Stack S)
{
    if(S->top==-1)
        return 0;
    else
        return 1;
};
void push(char X, Stack S)
{
    S->array[++S->top]=X;
};
char pop(Stack S)
{
    return S->array[S->top--];
};
void deleteStack(Stack S)
{
    while (S->top>=0)
    {
        free(S->array[S->top]);
        S->top--;
    }

};

int main (void)
{
    Stack S1=makeEmpty();
    char input[100], result[30], result1;
    char *word;
    int cnt=0,cnt2=0, temp=0, k=0, i,j,l;
    word=strtok(input, " ");
    char *str[20];

    while(1){
        if(fgets(input,100,stdin)){
            word=strtok(input, " ");//get input and tokenize
            cnt=0;
            while (word!=NULL)
            {
                str[cnt]=strdup(word);
                cnt++;
                word=strtok(NULL," ");  
            }       
        }

        for (i=0; i<cnt; i++)
        {
            if (strcmp(str[i],"(")==0 && (isEmpty(S1)==0))
            {
                push(str[i],S1);
                l++;
            }
            else if(strcmp(str[i],")")==0)
            {
                temp++;
                for(j=0; j<cnt2; j++)
                {
                    char result1=pop(S1);
                    result[k] =result1;
                    printf("%s ", result[k]);//This the place where I got runtime error
                    k++;
                }
                pop(S1);
                cnt2=0;     
            }
            else if(strcmp (str[i], "!")==0)
            {
                printf("in\n");
                deleteStack(S1);
                return 0;
            }

            else 
            {
                if  (isEmpty(S1)==1)
                {

                    if (l!=0)
                    {
                        push(str[i],S1);

                        if (strcmp(str[i],"(")!=0)
                        {
                            cnt2++;
                        }
                    }
                }
            }
        }
    }

    return 0;
}


Stack create(int c)
{
Stack S=(Stack)malloc(sizeof(struct stack));

    S->size=c;
    S->top=-1;
    S->array=(char *)malloc(sizeof(char)*c);

    return S;
}

Stack makeEmpty(void)
{
    Stack S1=create(100);
    S1[0].top=-1;
    return S1;
}
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
stella
  • 25
  • 1
  • 8
  • 2
    You're first 2 questions are too generic: how is "well" defined, for starters? Besides, you're asking 3 different question in one question. Only the last question has some merit, but it'd be better if you focus your code and question on just that: limit your code to a minimal example producing that error, and let us know what you've already done to debug your problem. –  Jan 03 '18 at 03:38
  • Possible duplicate of [C- Character Push and Pop operation](https://stackoverflow.com/questions/48069933/c-character-push-and-pop-operation) – Pablo Jan 03 '18 at 03:38
  • 1
    Also practical reading: https://ericlippert.com/2014/03/05/how-to-debug-small-programs/ –  Jan 03 '18 at 03:40
  • 1/ Don't cast `malloc` in C (and don't use `malloc` in C++; more on that if you ask about it). 2/ Don't hide levels of pointer indirection behind `typedef`. 3/ Your data structure logic should generally not decide whether or not `malloc` and `free` are used; in the world of C, that decision should go the person writing the entry point (`main`, or what-not for whatever dynamic library). As your project is presumably intended for use by other people, you should leave the decision with them as to how to expand their arrays... and... the best tool for the job is likely `pipe`, not `malloc`. – autistic Jan 03 '18 at 03:48
  • @pablo Thank you for your previous comments. I tried to follow yours, but it still doesn't work. So I thought the problem would not just in storing array from pop but also in other parts. As you commented, I changed S into *S by using typedef on top of the code. I thought it would be the same meaning as you commented but if it is not, could you explain to me..? Thank you so much for your help. – stella Jan 03 '18 at 03:48
  • Use `pipe` to create two file descriptors. Write to one when you're pushing, read from the other when you're popping. This tool was given to you for a reason. It may not be fast, but my guess is it'll compete with this, and scale far beyond... with less than half of the code... – autistic Jan 03 '18 at 04:01
  • 3
    @Sebivor just so you know `pipe` is not standard C but `POSIX`. Also, going to the operating system every time for a simple stack sounds a waste of resources. – Ajay Brahmakshatriya Jan 03 '18 at 04:12
  • 1
    @Sebivor: I believe a pipe would give a FIFO (first-in, first-out) discipline, not a stack (LIFO — last-in, first-out) discipline. There's a reason `mkfifo()` is used to create 'named pipes'. – Jonathan Leffler Jan 03 '18 at 04:29
  • It's very important that you improve the indentation of your code. The current formatting makes it difficult to read and, ergo, difficult for you to find good help. – Richard Jan 03 '18 at 04:36
  • @Richard I've made an edit for that. My edit is still on the peer review queue. – Pablo Jan 03 '18 at 04:37
  • @Pablo: Good work - I've voted for its approval. However, it's always good to remind new users that the best way of getting value out of a question is to put work into making a good question. (Incidentally, had I edited this myself, I'd probably have converted the bracing to [K&R style](https://en.wikipedia.org/wiki/Indentation_style#K&R) - I find it works better in the limited space SO gives.) – Richard Jan 03 '18 at 04:48
  • @Richard I try not to change to much of the user's style, but at least make the indentions consistent. I see I've missed one line in `create` though. – Pablo Jan 03 '18 at 04:55
  • Note that the semicolons after the close brace `}` at the end of a function is not part of the function syntax. Strictly, it marks the end of an empty declaration at file scope. Simply remove them. The semicolon is needed after variable and and type declarations or definitions at file scope. – Jonathan Leffler Jan 03 '18 at 05:53
  • @JonathanLeffler thanks for updating my code. I know that about the semicolons. It's just that I've been writing a lot of JavaScript lately and within my company's coding style are stuff like this `$scope.myfunf = function() { ... };` and I did it out of habit without realizing it. – Pablo Jan 03 '18 at 06:10

1 Answers1

2

Here you have again some things wrong. Before you create new threads with similar content, stick to one thread.

In your code you also never check if malloc fails. It's always better to do that. For simplicity I've omitted these checks in my suggestions.

1. Why do you do S1[0].top=-1; in makeEmpty? create already does that and writing in that way (instead of S1->top = -1) makes the code hard to interpret, because it could mean that you are treating the result of create as an array of Stacks. It's not wrong, it makes harder for us to interpret your intentions.

Stack makeEmpty(void)
{
    Stack S1=create(100);
    return S1;
}

is enough.

2. In push and pop you have to check first if the operations are valid. That means:

  • for push: check that you still have space to do the operation
  • for pop: check that you have at least one element on the stack.

The code could be:

int isFull(Stack S)
{
    return (S->size - 1 == S->top);
}

int push(char X, Stack S)
{
    if(isFull(S))
        return 0;

    S->array[++S->top]=X;
    return 1;
}

int pop(Stack S, char *val)
{
    if(isEmpty(S))
        return 0;

    *val = S->array[S->top--];
    return 1;
}

I changed the signatures of these functions to let the user know if the operation were successful. Otherwise you have no idea and you end up with undefined values. In main your should change the pop calls as well:

char el;
pop(S1, &el);

3. What do you want deleteStack to do: reset the stack or free the memory? You are mixing those in a bad way.

If you want to reset (meaning to pop all elements at once), then all you have to do is set top = -1. You don't have to free array. If you do, then you need to reallocate memory for array again.

When using free you can only pass to free the same pointer you've got from malloc/calloc/realloc. In your code you are passing a 8 bit integer as a pointer address and freeing that, that will make your program crash 100% of the time.

void deleteStack(Stack S)
{
    S->top = -1;
}

If you want to free the memory

void freeStack(Stack S)
{
    free(S->array);
    free(S);
}

but that also means that you cannot access the stack any more. Note that I changed the name of the function to make it more clear its intention.

If you use my suggestions, you have to change them in main as well, specially the pops.


EDIT: Sebivor's quote from the comments:

Don't hide levels of pointer indirection behind typedef

Yes, that also makes the code hard to read. In my suggestions I didn't change that, but I definitely would change

typedef struct stack Stack;

and in every function that has Stack S as argument change it to Stack *S. (See also Is it a good idea to typedef pointers — the short answer is 'No'.)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Pablo
  • 13,271
  • 4
  • 39
  • 59