C 堆栈函数中的堆缓冲区溢出

C 堆栈函数中的堆缓冲区溢出,c,struct,stack,dynamic-memory-allocation,function-definition,C,Struct,Stack,Dynamic Memory Allocation,Function Definition,因此,我创建了一个程序,使用一个名为stack的结构生成堆栈及其所有操作 结构: 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的结构生成堆栈及其所有操作

结构:

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函数的堆上有缓冲区溢出,我不明白为什么,因为我重新分配了我需要的字节,并释放了我不需要的字节

节目:

#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;
}
推送功能无效

if语句中的条件

if (s->sz+1 <= s->cap)
这是无效的。在realloc调用成功的情况下,s->v指向的内存被释放或重新使用。因此,再次调用free将调用未定义的行为。这就是是否将尝试释放已重新分配的内存,还是将释放新分配的内存

例如,可以通过以下方式定义功能推送

int push( stack *s, int e )
{
    int success = 0;

    if ( ( success = s->sz+1 < s->cap ) )
    {
        s->v[++s->sz] = e;
    }
    else
    {
        int *nv = realloc( s->v, sizeof( int ) * ( s->cap + 1 ) );
        success = nv != NULL;

        if ( success )
        {
            s->v = nv;
            ++s->cap;
            s->v[++s->sz] = e;
        }
    }

    return success;
}
程序输出为

The stack is empty
the current top value is 5
the current top value is 4
the current top value is 3
the current top value is 2
the current top value is 1
the current top value is 0
The stack isn't empty
这一行:

if (s->sz+1 <= s->cap)
正确的检查方法是,如果s->sz+1cap,或者甚至先增加值:

s->sz++;

if (s->sz < s->cap) {
    // ...
这也是错误的。首先,假设realloc分配新内存,并且需要释放旧的缓冲区:如果不需要,realloc会在需要时为您这样做。第二,您假设realloc不会在代码中的其他任何地方(malloc、calloc等)失败。第三,您在代码中的其他任何地方再次强制转换返回值,这是您不应该看到的

你应该做的是:

nv = realloc(s->v, sizeof(int)*s->cap);
if (nv == NULL) {
    // Handle error, abort execution.
}

s->v = nv;

应在每次调用malloc、realloc或calloc后检查nv==NULL。

调用未定义行为的不是if语句中的条件。@MarcoBonelli错误的条件是调用未定义行为的原因。确切地说,新的措辞要好得多:我照你说的做了,我想并重新输入了push到这个无效的pushstack*s,int e{s->sz++;if s->szcap{s->v[s->sz]=e;}else{int*nv;s->cap++;nv=reallocs->v,sizeofint*s->cap;if nv==NULL{}s->v=nv;s->v[s->sz]=e;}}并且它仍然会导致缓冲区溢出,因此如果您能够编写修改后的版本,我将非常感激,因为我仍然不理解我的错误is@MartimCorreia在第二种情况下,将s->sz增加两次,从else中删除s->sz++是的,我只是这么做了,我只是在睡觉的时候才明白你的意思,谢谢你
s->sz++;         // 4
s->v[s->sz] = e; // s->v[4] overflow!
s->sz++;

if (s->sz < s->cap) {
    // ...
nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
s->v = nv;
nv = realloc(s->v, sizeof(int)*s->cap);
if (nv == NULL) {
    // Handle error, abort execution.
}

s->v = nv;