Menu
CoddyTech

泛型栈

本课属于 Coddy C 学习旅程的“面向对象编程”单元。第 60 课,共 61 课。

challenge icon

挑战

简单

栈是一种基础数据结构,遵循后进先出(LIFO)原则:最后添加的元素最先移除。可以把它想象成一摞盘子:从顶部放入,也从顶部取出。

让我们来构建一个通用栈:一种使用 void* 指针存储任意类型数据的灵活数据结构。你的栈将遵循后进先出原则,并包含所有必要的操作。

你将把代码分成 3 个文件:

  • stack.h:定义 Stack 结构体,包含 3 个成员:用于存放元素的 void** 数组、表示栈顶索引(下一个空闲位置)的 int,以及表示容量的 int。声明用于创建栈(接收一个容量)、压入元素、弹出元素、查看栈顶元素、检查栈是否为空,以及释放栈的函数原型。
  • stack.c:实现通用栈:
    • create_stack:在堆上分配一个 Stack,按给定容量分配元素数组,将 top 初始化为 0,并返回指针
    • push:如果还有空间(即 top 小于 capacity),就将元素添加到栈顶
    • pop:移除并返回栈顶元素;如果栈为空,则返回 NULL
    • peek:返回栈顶元素但不移除;如果栈为空,则返回 NULL
    • is_empty:如果栈中没有元素,则返回 1;否则返回 0
    • free_stack:先释放元素数组,再释放 Stack 结构体本身
  • main.c:读取要执行的操作数量。然后对每个操作读取一条命令:push 后跟一个整数值、pop 或 peek。创建一个容量为 10 的栈。对于 push,在堆上分配一个整数并压入它的指针。对于 pop,取出元素,打印它的值,并释放该整数。对于 peek,打印值但不移除元素。如果在空栈上调用 pop 或 peek,则打印 empty。执行完所有操作后,释放剩余元素和栈。

程序将接收以下输入:

  1. 操作数量
  2. 每行一条操作(push X、pop 或 peek)

输入依次为 5、push 10、push 20、peek、pop、pop 时的输出示例:

20
20
10

输入依次为 3、pop、push 42、peek 时的输出示例:

empty
42

输入依次为 4、push 5、push 15、pop、pop 时的输出示例:

15
5

请记住,你的栈存储的是 void* 指针:实际数据由调用者负责分配和释放。弹出元素时,将返回的 void* 转换回 int*,以访问其值。使用 <string.h> 中的 strcmp 比较命令字符串。

亲手试试

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

int main() {
    int n;
    scanf("%d", &n);
    
    // TODO: 创建一个容量为 10 的栈
    
    // TODO: 处理每个操作
    for (int i = 0; i < n; i++) {
        char command[10];
        scanf("%s", command);
        
        if (strcmp(command, "push") == 0) {
            int value;
            scanf("%d", &value);
            // TODO: 在堆上为一个整数分配内存,并将其指针压入栈
        }
        else if (strcmp(command, "pop") == 0) {
            // TODO: 弹出栈顶元素
            // 如果不是 NULL,打印值并释放该整数
            // 如果是 NULL(栈为空),打印 "empty"
        }
        else if (strcmp(command, "peek") == 0) {
            // TODO: 查看栈顶元素
            // 如果不是 NULL,打印值(不要移除或释放)
            // 如果是 NULL(栈为空),打印 "empty"
        }
    }
    
    // TODO: 释放栈中剩余的所有元素
    // TODO: 释放栈本身
    
    return 0;
}

面向对象编程中的所有课

自己练习: C 在线编译器