用C语言写的简单的顺序栈,编译可以通过运行后什么也不显示

如题,代码奉上,请各位帮忙看一下错在哪了

#include <stdio.h>
#include <stdlib.h>
struct _ListStack
{
    struct NodeInt *first;
    struct NodeInt *last;
    int n;
    int top;
};
struct NodeInt
{
    int value;
    struct NodeInt *next;
};
void InitStack(_ListStack *s);
int Push(_ListStack *s, int v);
int Pop(_ListStack *s, int *v);
int Empty(_ListStack *s);
int GetTop(_ListStack *s, int *v);
int main(void)
{
    _ListStack sl1;
    int r;
    int ch;
    int v;
    InitStack(&sl1);
    /*Push(&sl1, 10);
    Push(&sl1, 20);
    Push(&sl1, 30);
    Push(&sl1, 40);*/
    ch=-1;
    while(ch)
    {
        printf("------------------\n");
        printf("1 - Push\n");
        printf("2 - Pop\n");
        printf("3 - GetTop\n");
        printf("4 - Empty\n");
        printf("0 - Exit\n");
        printf("------------------\n");
        printf("Select:");
        scanf("%d", &ch);
                ch=1;
        switch(ch)
        {
        case 1:
            printf("输入值:");
            scanf("%d", &v);
            r = Push(&sl1, v);
            printf("OK, n = %d\n", sl1.n);            
            break;

        case 2:
            r = Pop(&sl1, &v);
            switch(r)
            {
            case 0:
                printf("OK, n = %d,出栈的是%d\n", sl1.n, v);
                break;
            case -1:
                printf("Error: 栈为空\n");
                break;
            }
            break;

        case 3:
            r = GetTop(&sl1, &v);
            switch(r)
            {
            case 0:
                printf("OK, 栈顶内容是%d\n", v);
                break;
            case -1:
                printf("Error: 栈是空的\n");
                break;
            }
            break;
        }
        
    }
    
    return 0;
    
}

void InitStack(_ListStack *s)
{
    s->n = 0;
    s->top=0;
    s->first->next=NULL;
    s->last=s->first;
}
int Push(_ListStack *s, int v)
{    
    if(s->n==0)
    {
    s->last->value=v;
    s->top++;
    s->n++;
    }else
    {
    struct NodeInt *p;    
    p=s->last->next;
    p->value=v;
    s->n++;
    s->top++;
    }      
    return 0;
}
int Pop(_ListStack *s, int *v)
{
    if(s->n==0)
    {
        return -1;
    }
    *v = s->last->value;

    s->top--;

    s->n--;
    return 0;
}
int GetTop(_ListStack *s, int *v)
{
    if(s->top == 0)
    {
    return -1;
    }
        
    *v = s->last->value;
    return 0;

}
int Empty(_ListStack *s)
{
    return s->n == 0;
}


void InitStack(_ListStack *s)
{
    s->n = 0;
    s->top=0;
    s->first->next=NULL;
    s->last=s->first;
}
这个初始化函数就错了,s->first还没有分配空间呢,你就进行->next操作,必死无疑,所以后面的菜单都可能显示的
改为s->first = NULL;

printf("------------------\n");

这一行也不执行么?

  1. 首先,你这个不是顺序栈哦,这是链式栈;
  2. 没有看到动态分配内存的地方;
  3. 如果是顺序栈的话,我给你个大致的模板可以参考下:

栈的顺序表实现

1、数据结构定义

对于顺序表,在 C语言 中表现为 数组,在进行 栈的定义 之前,我们需要考虑以下几个点:
  1)栈数据的存储方式,以及栈数据的数据类型;
  2)栈的大小;
  3)栈顶指针;

  • 我们可以定义一个 结构体,C语言实现如下所示:
#define DataType int        // (1)
#define maxn 100005         // (2)

struct Stack {              // (3)
    DataType data[maxn];    // (4)
    int top;                // (5)
};
  • $(1)$ 用DataType这个宏定义来统一代表栈中数据的类型,这里将它定义为整型,根据需要可以定义成其它类型,例如浮点型、字符型、结构体 等等;
  • $(2)$ maxn代表我们定义的栈的最大元素个数;
  • $(3)$ Stack就是我们接下来会用到的 栈结构体
  • $(4)$ DataType data[maxn]作为栈元素的存储方式,数据类型为DataType,可以自行定制;
  • $(5)$ top即栈顶指针,data[top-1]表示栈顶元素,top == 0代表空栈;

2、入栈

1、动画演示

  如图所示,蓝色元素 为原本在栈中的元素,红色元素 为当前需要 入栈 的元素,执行完毕以后,栈顶指针加一。具体来看下代码实现。

2、源码详解

  • 入栈 操作,算上函数参数列表,总共也才几句话,代码实现如下:
    void StackPushStack(struct Stack *stk, DataType dt) { // (1)
      stk->data[ stk->top ] = dt;                       // (2)
      stk->top = stk->top + 1;                          // (3)
    }
    
  • $(1)$ stk是一个指向栈对象的指针,由于这个接口会修改栈对象的成员变量,所以这里必须传指针,否则,就会导致函数执行完毕,传参对象没有任何改变;
  • $(2)$ 将传参的元素放入栈中;
  • $(3)$ 将栈顶指针自增 1;
  • 注意,这个接口在调用前,需要保证 栈顶指针 小于 栈元素最大个数,即stk->top < maxn
  • 如果 C语言 写的熟练,我们可以把 $(2)$ 和 $(3)$ 合成一句话,如下:
void StackPushStack(struct Stack *stk, DataType dt) {
    stk->data[ stk->top++ ] = dt;                    
}
  • stk->top++表达式的值是自增前的值,并且自身进行了一次自增。

    3、出栈

    1、动画演示

      如图所示,蓝色元素 为原本在栈中的元素,红色元素 为当前需要 出栈 的元素,执行完毕以后,栈顶的指针减一。具体来看下代码实现。

    2、源码详解

  • 出栈 操作,只需要简单改变将 栈顶 减一 即可,代码实现如下:
    void StackPopStack(struct Stack* stk) {
      --stk->top;
    }
    

    4、清空栈

    1、动画演示

      如图所示,对于数组来说,清空栈的操作只需要将 栈顶指针 置为栈底,也就是数组下标 0 即可,下次继续 入栈 的时候会将之前的内存重复利用。

    2、源码详解

  • 清空栈的操作只需要将 栈顶 指针直接指向 栈底 即可,对于顺序表,也就是 C语言 中的数组来说,栈底 就是下标 0 的位置了,代码实现如下:
    void StackClear(struct Stack* stk) {
      stk->top = 0;
    }
    

    5、只读接口

  • 只读接口包含:获取栈顶元素、获取栈大小、栈的判空,实现如下:
    DataType StackGetTop(struct Stack* stk) {
      return stk->data[ stk->top - 1 ];      // (1)
    }
    int StackGetSize(struct Stack* stk) {
      return stk->top;                       // (2)
    }
    bool StackIsEmpty(struct Stack* stk) {
      return !StackGetSize(stk);             // (3)
    }
    
  • $(1)$ 数组中栈元素从 0 开始计数,所以实际获取元素时,下标为 栈顶元素下标 减一;
  • $(2)$ 因为只有在入栈的时候,栈顶指针才会加一,所以它 正好代表了 栈元素个数;
  • $(3)$ 当 栈元素 个数为 零 时,栈为空。

    6、栈的顺序表实现源码

  • 栈的顺序表实现的源码如下:
/************************************* 栈的顺序表实现 *************************************/
#define DataType int
#define bool int
#define maxn 100010

struct Stack {
    DataType data[maxn];
    int top;
};

void StackClear(struct Stack* stk) {
    stk->top = 0;
}
void StackPushStack(struct Stack *stk, DataType dt) {
    stk->data[ stk->top++ ] = dt;
}
void StackPopStack(struct Stack* stk) {
    --stk->top;
}
DataType StackGetTop(struct Stack* stk) {
    return stk->data[ stk->top - 1 ];
}
int StackGetSize(struct Stack* stk) {
    return stk->top;
}
bool StackIsEmpty(struct Stack* stk) {
    return !StackGetSize(stk);
}
/************************************* 栈的顺序表实现 *************************************/