【问题标题】:working with stack and pointers in c在c中使用堆栈和指针
【发布时间】:2018-05-21 00:42:11
【问题描述】:

我正在用 c 编写非常简单的函数来操作堆栈。一切正常,但我想知道如何创建一个 createstack() 函数,该函数将指针设置为创建一个空堆栈。以及如何在我的推送和弹出功能中使用此功能或结构。 这是我的代码:

 

typedef struct nodeRec
{
    int item;
    struct nodeRec* next;
} node;
typedef node* nodePtr;
nodePtr top;


int isempty(nodePtr mytop)
{
    return mytop == NULL;
}

void push(int value1, nodePtr* mytop)
{
    struct nodeRec *newNode;
    newNode = (struct nodeRec*)malloc(sizeof(struct nodeRec));
    newNode->item = value1;
    if (isempty(mytop))
        newNode->next = NULL;
    else
        newNode->next = mytop;
    top = newNode;
    printf("\nElement added!!!\n");
    count++;
}
void pop(nodePtr* mytop)
{
    if (isempty(mytop))
        printf("\nStack is Empty!!!\n");
else {
    struct nodeRec *temp = mytop;
    printf("\nDeleted element: %d", temp->item);
    top= temp->next;
    free(temp);
    count--;
}

}

【问题讨论】:

  • 您的代码存在一些问题。例如,nodePtr* mytop 的类型为 node**,但您将其视为 node*
  • 这是一个很好的例子,说明为什么为指针设置类型别名是个坏主意。请不要这样做,它会招致像你这样的错误。此外,你的编译器应该已经告诉你所有这些问题,可能很清楚。
  • 好的。我应该省略 nodePtr* mytop 并将 mytop 替换为 top。这工作得很好。但是我的编译器什么也没说,这些函数都起作用了
  • 使用您使用的堆栈设计,您永远不需要createStack 函数。 nodePtr stack = NULL; push(value, &stack);pop(&stack); 工作正常。另外,你做错的是newNode->next = mytop;(应该是*mytop)。同样,您需要在pushpop 中使用isempty(*mytop)
  • 函数“工作”是因为您使用全局变量 top 而不是局部变量 mytop。我建议你停止使用全局变量,并做一些关于在 C 中模拟传递引用的研究。

标签: c stack


【解决方案1】:

你可以这样做:

typedef struct {
    node *head;
    size_t size;
} stack_t;

size_t stack_size(stack_t *stack) {
    return stack->size;
}

bool is_empty(stack_t *stack) {
    return stack_size(stack) == 0;
}

stack_t *stack_create(void) {
    stack_t *stack = malloc(sizeof(stack_t));
    stack->size = 0;
    stack->head = NULL;
    return stack;
}

void push(stack_t *stack, int data) {
    node *new_node = malloc(sizeof(struct nodeRec));
    new_node->item = data;
    new_node->next = stack->head;
    stack->head = new_node;
    stack->size++;
}

int pop(stack_t *stack) {
    assert(!is_empty(stack));
    node *old_head = stack->head;
    stack->head = stack->head->next;
    int ret = old_head->item;
    free(old_head);
    stack->size--;
    return ret;
}

当然,这不是一个超级健壮的实现,因为它忽略了一些情况,例如将无效参数(例如 NULL 指针)传递到堆栈接口函数时,以及诸如 malloc 失败的错误情况,但是希望这是一个好的开始。

基本思想是我们定义一个类型stack_t,它存储您当前存储在全局变量中的所有元数据。然后,我们的stack_create 函数只需要为这些stack_t 类型之一分配内存并初始化,我们可以返回一个指向它的指针。这样,您可以轻松地拥有多个堆栈,每个堆栈都有自己的 stack_t 标头,可以传递给所有堆栈接口函数。

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    您的示例是由链表支持的堆栈。所以在那种情况下,你只需要维护一个指向头部的指针;

    struct stack {
       node *head;
    };
    

    在每个操作中,根据需要更新head

    void stack_push(stack *s, int val) {
        node *node = (node *) malloc(sizeof(node));
        node->item = val;
        node->next = s->head;
        s->head = node;
    }
    

    编辑

    @Osiris 在 cmets 中提问:

    node *stack 是否可以正常工作?

    这是一个坏主意的原因是指针别名:

    /* Declare the stack using Osiris' type */
    node *stack1 = ...;
    node *stack2 = stack1;
    
    stack_pop(&stack1);
    stack_push(&stack2, 0);  /* Crash accessing freed memory */
    

    显然,这些参考资料可能很多,并且分布在不同的模块中。没有办法保证不存在指针别名。您无法知道您的node * 在任何给定时间是否有效。这就是为什么将堆栈简单地表示为建议的 node * 不起作用的原因。

    但是,使用结构体,通过一个引用执行的操作不可能与另一个引用上的操作发生冲突:

    stack *stack1 = ...;
    stack *stack2 = stack1;
    
    stack_pop(stack1);
    stack_push(stack2, 0); /* No crash */
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-18
      • 2015-08-05
      • 1970-01-01
      • 2014-06-21
      • 2013-12-13
      • 1970-01-01
      • 2021-09-17
      相关资源
      最近更新 更多