1

假设我在 C 中有以下代码表示堆栈:

#define MAX 1000

int arr[MAX];
static int counter = 0;
isstackempty()
{
    return counter <= 0;
}
void push(int n)
{
    if (counter >= MAX) {
        printf("Stack is full.  Couldn't push %d", n);
        return;
    }
    arr[counter++] = n;
}

int pop(int* n)
{
    if(isstackempty() || n == 0) {
        printf("Stack is empty\n");
        return 0;
    }
    *n = arr[--counter];
    return 1;
}

上面的代码在一个stack.c文件中,函数原型在一个头文件中。


现在,来自 C# 和 OO 背景,如果我想分隔stacks 以在我的应用程序中使用,我会在 OO 语言中创建两个实例。但是在 C 中,你如何处理这样的场景呢?

假设我想stack在我的 C 代码中使用两个单独的 s ......使用上面的代码,我该怎么做?

4

7 回答 7

10

将数组arr放入struct.

struct stack {
    int arr[MAX];
    ...
}

这个结构成为你的实例。然后,您可以在堆栈上声明它:

struct stack mystack;

或在堆上使用malloc

struct stack *mystack = malloc(sizeof(struct stack));

您还需要将指向该实例的指针作为第一个参数传递给任何操作该实例的函数。

于 2009-08-07T10:33:27.013 回答
7

这样做的 C 方法是将“对象”的所有状态包装到一个结构中,然后将其显式传递给所有在堆栈上操作的函数,所以它应该是:

typedef struct _stack {
  int arr[MAX];
  int counter;
} stack;

int isstackempty(stack *s)
{
    return s->counter <= 0;
}

int push(stack *s, int n)
{
    if (s->counter >= MAX) {
        printf("Stack is full.  Couldn't push %d", n);
        return -1;
    }
    arr[s->counter++] = n;
    return 0
}

int pop(stack *s, int *n)
{
    if(isstackempty(s) || n == 0) {
        printf("Stack is empty\n");
        return -1;
    }
    *n = arr[--s->counter];
    return 0;
}

您的示例的问题是您正在编写函数定义,就像我们有一个基于类的对象结构一样,而 C 没有。想一想它是如何在 C 中完成的,最简单的方法是编写需要显式传入“this”参数的方法。

您也可以拥有等效的构造函数和析构函数,它们可以进一步抽象您的“对象”。

stack* newStack() {
    stack* s = malloc(sizeof(stack));
    s->counter = 0;
    return s;
}

void freeStack(stack* s) {
    free(s);
}
于 2009-08-07T10:42:07.527 回答
3

一种(非常简单的)方法是定义一个表示堆栈的结构:

typedef struct {
    int arr[MAX];
    int counter = 0;
} myStack;

然后重写push()pop()操作一个实例myStack

int push(myStack *s, int n)
{
    if (s->counter >= MAX) {
        printf("Stack is full.  Couldn't push %d", n);
        return -1;
    }
    s->arr[(s->counter)++] = n;
    return s->counter;
}

int pop(myStack *s, int* n)
{
    if(0 == s->counter || 0 == n) {
        printf("Stack is empty\n");
        return -1;
    }
    *n = s->arr[--(s->counter)];
    return 1;
}

(还在 .YMMV 中添加了有意义的返回值和错误值push()。)

于 2009-08-07T10:43:05.530 回答
1

只需使您的“this”指针明确:

struct stack* create_stack();
void push(struct stack* mystack, int n);
void pop(struct stack* mystack, int* n);
于 2009-08-07T10:34:28.993 回答
1

我希望你觉得这篇论文有用。它为您的问题提供了不止一个答案:)

堆叠猫的十六种方法

于 2009-08-07T10:35:20.397 回答
0

对另一个问题的回答有一个完整的 C 中 OO 数据缓冲区结构的工作示例。

于 2009-08-08T02:56:17.990 回答
0

动态分配的每个实例的结构是正确的方法。一个细节点——如果你正在编写一个更常用的 API,那么为了更好的抽象而进行数据隐藏可能是一个好主意。最简单的方法是在 C 文件(或私有头文件)中保留内部结构的定义,并 typedef 一个指向(例如)' stack_handle_t'的空指针。正是这种类型从您的“构造函数”返回并传递回其他函数。实现知道句柄的值实际上是一个指向结构的指针,并且在每个函数的开头简单地做:

int pop(stack_handle_t handle, int* n)
{
    stack *p_stack = (stack *)handle;
    ...

比这更好的是使用内部分配的标识符,无论这是对这些结构数组的索引,还是仅仅是可以与(链接?)结构列表之一匹配的标识符。显然,如果它仅用于您的项目内部,那么所有这些都是无关紧要的,在这种情况下,它只会进行不必要的工作和过度复杂化。

于 2009-08-08T13:02:08.563 回答