所以我创建了一个程序,该程序使用称为栈的结构来制作栈及其所有操作。
结构:
typedef struct {
int *v; /* contents of the stack */
int cap; /* capacity of v, i.e. how many elements can fit in v */
int sz; /* number of elements currently stored in v */
} stack;
程序运行良好,但是当我使用fsantize
时,它说在Push函数中堆上有缓冲区溢出,我不明白为什么,因为ive重新分配了我需要的字节并释放了我不需要的字节。
程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int *v; /* contents of the stack */
int cap; /* capacity of v, i.e. how many elements can fit in v */
int sz; /* number of elements currently stored in v */
} stack;
void init(stack * s)
{
s->v = (int*) calloc(4,sizeof(int));
s->cap = 4;
s->sz = -1;
}
int is_empty(stack * s)
{
if (s->sz == -1)
return 1;
else
return 0;
}
void push(stack * s, int e)
{
if (s->sz+1 <= s->cap)
{
s->sz++;
s->v[s->sz] = e;
}
else
{
int *nv;
s->cap++;
s->sz++;
nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
s->v = nv;
s->v[s->sz] = e;
}
}
int pop(stack * s)
{
if (is_empty(s) == 0)
{
int top = s->v[s->sz];
s->sz--;
return top;
}
else
{
printf("Impossible the stack isn't empty\n");
return 0;
}
}
void destroy(stack * s)
{
//frees the stack bytes that were allocated
free(s->v);
free(s);
}
int main()
{
int i;
stack *pilha = (stack*) malloc(sizeof(stack));
init(pilha);
if (is_empty(pilha) == 1)
printf("The stack is empty\n");
pop(pilha);
for (i = 0; i<=4;i++)
push(pilha,i);
push(pilha,5);
printf("The top is:%d\n",pilha->v[pilha->sz]);
if (is_empty(pilha) == 0)
printf("The stack isn't empty\n");
destroy(pilha);
return 0;
}
功能push
无效。
if语句中的此条件
if (s->sz+1 <= s->cap)
调用未定义的行为。假设s-> cap等于1。因此,您可以仅推送一个元素,而无需调整数组的大小。因此,在推入新值后,s-> sz将等于0。并且,如果不调整数组大小,则可能无法推入新值。但是,if语句中的条件将计算为true,并且您将写入分配的数组之外的内存。
也是此代码段
nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
无效。在成功调用realloc的情况下,释放了s-> v指向的内存(或重新使用了r)。因此,再次调用free将调用未定义的行为。那就是将尝试释放已重新分配的内存还是将释放新分配的内存。
此行:
if (s->sz+1 <= s->cap)
包含逻辑错误:如果s->sz+1 == s->cap
,则需要更多空间。例如,如果s->cap
为4
,则只有4
个元素(索引从0
到3
的空间),但是对于s->sz == 3
,则输入if
,结果为:
s->sz++; // 4
s->v[s->sz] = e; // s->v[4] overflow!
正确的检查方法是if (s->sz+1 < s->cap)
,甚至先递增该值:
s->sz++;
if (s->sz < s->cap) {
// ...
此:
nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
s->v = nv;
也是错误的。首先,假设realloc
分配了新的内存,并且需要free
旧的缓冲区:您没有,realloc()
会在需要时为您执行此操作。其次,假设realloc()
不会失败(就像您在代码中的其他任何地方所做的一样,malloc
,calloc
等)。第三,您正在强制转换返回值(同样,就像在代码中的其他任何地方一样),您不应该这样做(请参阅Do I cast the result of malloc?)。
您应该做的是:
nv = realloc(s->v, sizeof(int)*s->cap);
if (nv == NULL) {
// Handle error, abort execution.
}
s->v = nv;