PHP pop()函数问题

时间:2013-11-25 03:24:48

标签: c stack pop

所以我的pop()函数有问题,在运行我的程序时,第一次调用pop()函数时它返回的项没问题,但是当它试图连续弹出第二个项时, 它失败。我似乎无法弄清楚为什么,我的功能中是否有一些东西缺失?

#define DEFAULT_CAPACITY 16

struct stack {
   size_t capacity;
   size_t size;
   stack_item *data;
};

stack *new_stack (void) {
   stack *this = malloc (sizeof (stack));
   assert (this != NULL);
   this->capacity = DEFAULT_CAPACITY;
   this->size = 0;
   this->data = calloc (this->capacity, sizeof (stack_item));
   assert (this->data != NULL);
   return this;
}

void free_stack (stack *this) {
   assert (empty_stack (this));
   free (this->data);
   free (this);
}

static bool full_stack (stack *this) {
  return this->size == this->capacity;
}

static void realloc_stack (stack *this) {
   size_t old_capacity = this->capacity;
   this->capacity *= 2;
   this->data = realloc (this->data, this->capacity);
   memset (this->data + old_capacity, 0, old_capacity);
   assert (this->data != NULL);
}


void push_stack (stack *this, stack_item item) {
   if (full_stack (this)) realloc_stack (this);
   //increase size of stack
   this->data[this->size] = item;
   this->size++;
}

stack_item pop_stack (stack *this) {
   assert (! empty_stack (this));
   printf("Stack size: %lu\n", this->size);
   return this->data[this->size--];
}

1 个答案:

答案 0 :(得分:2)

取决于“失败”的含义。

它可能会失败的原因有很多,例如(并非详尽无遗):

  • 推送数据的代码不正确。
  • 你没有创造足够大的容量。
  • 你没有推出足够的项目来弹出(堆栈下溢)。

你应该做的第一个事情就是创建一个dump_stack函数来进行调试,其中包括:

void dump_stack (char *desc, stack *this) {
    printf ("%s: size/capacity: %lu/%lu\n",
        desc, this->size, this->capacity);
    for (size_t idx = 0; idx < this->size; idx++) {
        // print out this->data[idx], depends on data type
    }
}

如果你在每次堆叠操作后调用它(push,pop,peek,clear,dup,rot,2dup,3rot等等),这将极大地帮助你找出你的问题所在。


现在您已经添加了更多代码,您需要查看一些内容。

首先,您的stack_item类型。除非这与char的大小完全相同,否则您的内存分配功能不正确。例如,如果它是一个四字节整数,则需要分配四倍于当前内存的内存。这可以通过将分配乘以sizeof(stack_item)来解决。

您已使用初始calloc调用完成此操作(因为您必须提供相应的大小),但不会在后续的realloc调用中。


其次,在realloc_stack函数中,您在执行assert之前确实应该memset。如果由于某种原因,重新分配失败,那么对内存执行任何并不是一个好主意。


第三,依靠assert来捕捉运行时可能发生或可能不发生的错误是一个坏主意。那是因为assert通常在非调试代码中没有做任何事情(基于NDEBUG)所以,如果你的内存不足,你就不会抓住它。您可能需要结合exit()(例如)提供自己的错误处理内容。

我也不是真正喜欢图书馆类型代码的忠实粉丝,如果它有问题,请从你的下面拉出地毯 - 我总是喜欢让它给调用者返回一个指示并让那个决定做什么(这就是为什么我永远不会在生产代码中使用GMP的原因,因为它在内存不足时完全正确)。


第四,使用callocmemset几乎肯定是浪费,因为您的代码知道堆栈末端基于size的位置。将size以上但capacity以下的条目设置为0或某个任意值是无关紧要的,因为如果没有先将它们设置为某些内容(使用推送操作),您将永远不会使用它们。