奇怪的堆栈实现错误
只是为了好玩,我实现了自己的堆栈,但是,没有使用链表,但它仍然是动态的,因为每次你推入它或弹出它时,它都会 malloc 是一个更大或更小的新数组,并且然后用已经存在的东西填充它(少一或多一)。我知道这是非常缓慢且愚蠢的方法,但是,我只是想看看它是否有效。
代码有点长,所以我将其粘贴到此处:
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int size;
int *stack_array;
}stack;
void newStack(stack *a) {
a->size = 0;
a->stack_array = malloc(sizeof(int) * 1);
}
void push(stack *a, int x) {
int *new_array = malloc(sizeof(int) * a->size);
int i;
for(i=0; i < a->size; i++) {
new_array[i] = a->stack_array[i];
}
new_array[i] = x;
a->stack_array = new_array;
a->size += 1;
}
int pop(stack *a) {
if(a->size <= 0) {
printf("CALL POP() WITH FILLED STACK");
exit(1);
}
int *new_array = malloc(sizeof(int) * (a->size)-1);
int i;
for(i=0; i < a->size-1; i++) {
new_array[i] = a->stack_array[i];
}
int popped = a->stack_array[i];
a->stack_array = new_array;
a->size -= 1;
return popped;
}
void printStack(stack *a) {
int i;
printf("{");
for(i=0; i<a->size-1; i++) {
printf("%d, ", (a->stack_array)[i]);
}
printf("%d}\n", (a->stack_array)[i]);
}
int main (void) {
stack a;
newStack(&a);
push(&a, 6);
push(&a, 12);
push(&a, 13);
printStack(&a);
printf("Popped: %d\n", pop(&a));
printStack(&a);
return 0;
}
而且,如您所见,它工作得很好。
现在,当我向它添加一个循环时,要向堆栈中添加更多内容(粘贴此处):
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int size;
int *stack_array;
}stack;
void newStack(stack *a) {
a->size = 0;
a->stack_array = malloc(sizeof(int) * 1);
}
void push(stack *a, int x) {
int *new_array = malloc(sizeof(int) * a->size);
int i;
for(i=0; i < a->size; i++) {
new_array[i] = a->stack_array[i];
}
new_array[i] = x;
a->stack_array = new_array;
a->size += 1;
}
int pop(stack *a) {
if(a->size <= 0) {
printf("CALL POP() WITH FILLED STACK");
exit(1);
}
int *new_array = malloc(sizeof(int) * (a->size)-1);
int i;
for(i=0; i < a->size-1; i++) {
new_array[i] = a->stack_array[i];
}
int popped = a->stack_array[i];
a->stack_array = new_array;
a->size -= 1;
return popped;
}
void printStack(stack *a) {
int i;
printf("{");
for(i=0; i<a->size-1; i++) {
printf("%d, ", (a->stack_array)[i]);
}
printf("%d}\n", (a->stack_array)[i]);
}
int main (void) {
stack a;
newStack(&a);
int i = 0;
for(i = 0; i<12; i++) {
push(&a, i);
}
printStack(&a);
return 0;
}
它运行在键盘上很好(这让我更加困惑),但是,在我的机器上,它给了我这个错误(我以前从未见过,这是在运行时给出的):
a.out: malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted
它可能会或可能不会产生影响机器运行这是一个 VirtualBox Linux 机器。另外,我显然没有很好地编写实现,因为它没有释放任何指针或空间,也没有检查许多错误。
Just for fun, I implemented my own stack, but, without using a linked list, but it was still dynamic, because every time you push on it, or pop off it, it malloc's a new array of a bigger or smaller size, and then fills it with what was already there (and one less or one more). I understand that this is very slow and a stupid way to do it, but, I just wanted to see if it works.
The code is sort of long, so I pastied it here:
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int size;
int *stack_array;
}stack;
void newStack(stack *a) {
a->size = 0;
a->stack_array = malloc(sizeof(int) * 1);
}
void push(stack *a, int x) {
int *new_array = malloc(sizeof(int) * a->size);
int i;
for(i=0; i < a->size; i++) {
new_array[i] = a->stack_array[i];
}
new_array[i] = x;
a->stack_array = new_array;
a->size += 1;
}
int pop(stack *a) {
if(a->size <= 0) {
printf("CALL POP() WITH FILLED STACK");
exit(1);
}
int *new_array = malloc(sizeof(int) * (a->size)-1);
int i;
for(i=0; i < a->size-1; i++) {
new_array[i] = a->stack_array[i];
}
int popped = a->stack_array[i];
a->stack_array = new_array;
a->size -= 1;
return popped;
}
void printStack(stack *a) {
int i;
printf("{");
for(i=0; i<a->size-1; i++) {
printf("%d, ", (a->stack_array)[i]);
}
printf("%d}\n", (a->stack_array)[i]);
}
int main (void) {
stack a;
newStack(&a);
push(&a, 6);
push(&a, 12);
push(&a, 13);
printStack(&a);
printf("Popped: %d\n", pop(&a));
printStack(&a);
return 0;
}
And, as you can see, it works just fine.
Now, when I add a loop to it, to add a few more to the stack (pastied here):
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int size;
int *stack_array;
}stack;
void newStack(stack *a) {
a->size = 0;
a->stack_array = malloc(sizeof(int) * 1);
}
void push(stack *a, int x) {
int *new_array = malloc(sizeof(int) * a->size);
int i;
for(i=0; i < a->size; i++) {
new_array[i] = a->stack_array[i];
}
new_array[i] = x;
a->stack_array = new_array;
a->size += 1;
}
int pop(stack *a) {
if(a->size <= 0) {
printf("CALL POP() WITH FILLED STACK");
exit(1);
}
int *new_array = malloc(sizeof(int) * (a->size)-1);
int i;
for(i=0; i < a->size-1; i++) {
new_array[i] = a->stack_array[i];
}
int popped = a->stack_array[i];
a->stack_array = new_array;
a->size -= 1;
return popped;
}
void printStack(stack *a) {
int i;
printf("{");
for(i=0; i<a->size-1; i++) {
printf("%d, ", (a->stack_array)[i]);
}
printf("%d}\n", (a->stack_array)[i]);
}
int main (void) {
stack a;
newStack(&a);
int i = 0;
for(i = 0; i<12; i++) {
push(&a, i);
}
printStack(&a);
return 0;
}
It runs fine on codepad (which confuses me some more), but, on my machine, it gives me this error (which I have never seen before, and this is given at runtime):
a.out: malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted
It may or may not make a difference that the machine running this is a VirtualBox Linux machine. Also, I obviously have not written the implementation very well, seeing it doesn't free any pointers, or space, or check for many errors.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在
newStack
中,你这样说:所以
a->size
是最后一个元素的索引,而不是元素的数量。然后,在push
中,您执行以下操作:第一次,为
new_array
malloc
零字节,运行for< /code> 循环零次,然后将
x
分配给new_array[0]
。现在,您的堆因缓冲区溢出而损坏。你应该这样说:你也应该释放你的内存,也许你应该了解
realloc
和memcpy
。
In
newStack
, you say this:So
a->size
is the index of the last element, not the number of elements. Then, inpush
, you do this:The first time through, you
malloc
zero bytes fornew_array
, run through thefor
loop zero times, and then assignx
tonew_array[0]
. And you now have a corrupted heap from a buffer overflow. You should be saying this:You should also be freeing your memory and maybe you should learn about
realloc
andmemcpy
.当您将某些内容压入堆栈时,您分配的项目太少了。
push()
可能看起来像:在
pop()
中,即使在执行新分配时减一,由于运算符优先级,您也无法正确执行算术。这并不是一个真正的问题(就堆损坏而言),因为它会导致您的分配太大一点;您只是分配了一些您永远不会实际使用的字节。更不用说您的示例程序从未调用过它。尝试:您在评论中提到您尚未释放任何内存,因此下一步是正确释放不再使用的内存块,这样就不会泄漏......
When you push something onto the stack, you're allocating one too few items.
push()
should maybe look like:And in
pop()
, even though you subtract one when performing the new allocation you're not performing the arithmetic correctly because of operator precedence. This isn't really a problem (in terms of heap corruption) because it causes your allocation to be too large by a little bit; you're just allocating a few bytes that you'll never actually use. Not to mention that your example program doesn't ever call it. Try:You mention in a comment that you're not yet freeing any memory, so your next step is to properly free the memory blocks you're no longer using so there are no leaks...