所以我的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--];
}
答案 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
的原因,因为它在内存不足时完全正确)。
第四,使用calloc
和memset
几乎肯定是浪费,因为您的代码知道堆栈末端基于size
的位置。将size
以上但capacity
以下的条目设置为0
或某个任意值是无关紧要的,因为如果没有先将它们设置为某些内容(使用推送操作),您将永远不会使用它们。