(在C中)使用数组实现堆栈 - 当数组大小加倍时运行时错误

时间:2014-08-09 01:19:49

标签: c arrays stack double runtime-error

当我的数组已满时,我在doublestack()函数中使用realloc()将其加倍。这样做两次以上会给我一个运行时错误。 我想这可能是因为原始堆栈(使用create()函数创建的)的大小仍然相同,所以我也加倍了,并且消除了运行时错误。

我的问题:

  1. 这是实际发生的事吗?每次数组加倍时,堆栈需要加倍?

  2. 如果是,为什么原始堆栈能够首先支持对doublestack()的第一次和第二次调用?

  3. 你能否给我一个图形/内存映射说明我们realloc()数组和堆栈时究竟发生了什么?

  4. 我在浪费任何记忆吗?有没有更好的方法来使用数组实现堆栈?

  5. 非常感谢您的光临。

    CODE和OUTPUTS :(取消注释UNCOMMENT使用realloc()将堆栈大小加倍的地方

    #include <stdio.h>
    #include <stdlib.h>
    
    #define INIT_CAPACITY 1
    
    struct stack
    {
        int top;
        int capacity;
        int *array;
    };
    
    struct stack * create(int);
    void push(struct stack *,int);
    int top(struct stack *);
    int isfull(struct stack *);
    int isempty(struct stack *);
    void traverse(struct stack *);
    struct stack *doublestack(struct stack *);
    int pop(struct stack *);
    
    int main()
    {
        struct stack *S=create(INIT_CAPACITY);
        push(S,1);
        push(S,2);//First call to doublestack()
        push(S,3);//Second call to doublestack()
        push(S,4);
        push(S,5);//Third call to doublestack() - ERROR
        traverse(S);
    }
    
    struct stack * create(int capacity)//create a new stack with INIT_CAPACITY
    {
        struct stack *newstack=(struct stack *)malloc(sizeof(struct stack));
        if(!newstack)   return NULL;
        newstack->top=-1;
        newstack->capacity=capacity;
        newstack->array=(int *)malloc(sizeof(int)*(newstack->capacity));
        return newstack;
    
    }
    
    void push(struct stack *s,int data)
    {
        printf("\nCurrent stack is");
        traverse(s);
        printf("\nPushing %d onto stack:\n\n",data);
        if(isfull(s))
        {
            printf("\nStack is FULL.Now doubling...\n\n");
            doublestack(s);
        }
        (s->top)++;
        s->array[s->top]=data;
    }
    
    struct stack * doublestack(struct stack *s)//using realloc()
    {
        s=realloc(s,(sizeof(struct stack)*2));//**UNCOMMENT THIS TO ELIMINATE ERROR**
        s->capacity *= 2;
        s->array=realloc(s->array,s->capacity);
    }
    
    void traverse(struct stack *s)
    {
        printf("\n");
        int i;
        for(i=0;i <= s->top;i++)
        {
            printf("%d\t",s->array[i]);
        }
        printf("\n\n");
    }
    
    int top(struct stack *s)
    {
        return s->array[s->top];
    }
    
    int isfull(struct stack *s)
    {
        return (s->capacity)-1==s->top;
    }
    
    int isempty(struct stack *s)
    {
        return s->top==-1;
    }
    
    int pop(struct stack *s)
    {
        if(isempty(s))
        {
            printf("\nStack is EMPTY\n\n");
            return 0;
        }
        int data=s->array[s->top];
        s->top--;
        return data;
    }
    

    输出1 :(堆栈没有加倍,因此运行时错误)

    Current stack is
    
    Pushing 1 onto stack:
    
    Current stack is
    1   
    
    Pushing 2 onto stack:
    
    Stack is FULL.Now doubling...
    
    Current stack is
    1   2   
    
    Pushing 3 onto stack:
    
    Stack is FULL.Now doubling...
    
    Current stack is
    1   2   3   
    
    Pushing 4 onto stack:
    
    Current stack is
    1   2   3   4   
    
    Pushing 5 onto stack:
    
    Stack is FULL.Now doubling...
    
    *** glibc detected *** ./a.out: realloc(): invalid next size: 0x09191018 ***
    ======= Backtrace: =========
    /lib/i386-linux-gnu/i686/cmov/libc.so.6(+0x70f01)[0xb75e5f01]
    /lib/i386-linux-gnu/i686/cmov/libc.so.6(+0x7660d)[0xb75eb60d]
    /lib/i386-linux-gnu/i686/cmov/libc.so.6(realloc+0xdd)[0xb75eb8ed]
    ./a.out[0x8048674]
    ./a.out[0x804861c]
    ./a.out[0x8048569]
    /lib/i386-linux-gnu/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xb758be46]
    ./a.out[0x8048421]
    ======= Memory map: ========
    08048000-08049000 r-xp 00000000 08:07 549947     /home/user/a.out
    08049000-0804a000 rw-p 00000000 08:07 549947     /home/user/a.out
    09191000-091b2000 rw-p 00000000 00:00 0          [heap]
    b7400000-b7421000 rw-p 00000000 00:00 0 
    b7421000-b7500000 ---p 00000000 00:00 0 
    b7546000-b7562000 r-xp 00000000 08:07 548        /lib/i386-linux-gnu/libgcc_s.so.1
    b7562000-b7563000 rw-p 0001b000 08:07 548        /lib/i386-linux-gnu/libgcc_s.so.1
    b7574000-b7575000 rw-p 00000000 00:00 0 
    b7575000-b76d1000 r-xp 00000000 08:07 468        /lib/i386-linux-gnu/i686/cmov/libc-2.13.so
    b76d1000-b76d2000 ---p 0015c000 08:07 468        /lib/i386-linux-gnu/i686/cmov/libc-2.13.so
    b76d2000-b76d4000 r--p 0015c000 08:07 468        /lib/i386-linux-gnu/i686/cmov/libc-2.13.so
    b76d4000-b76d5000 rw-p 0015e000 08:07 468        /lib/i386-linux-gnu/i686/cmov/libc-2.13.so
    b76d5000-b76d8000 rw-p 00000000 00:00 0 
    b76e8000-b76eb000 rw-p 00000000 00:00 0 
    b76eb000-b76ec000 r-xp 00000000 00:00 0          [vdso]
    b76ec000-b7708000 r-xp 00000000 08:07 504        /lib/i386-linux-gnu/ld-2.13.so
    b7708000-b7709000 r--p 0001b000 08:07 504        /lib/i386-linux-gnu/ld-2.13.so
    b7709000-b770a000 rw-p 0001c000 08:07 504        /lib/i386-linux-gnu/ld-2.13.so
    bfb34000-bfb55000 rw-p 00000000 00:00 0          [stack]
    Aborted
    

    输出2 :(堆叠加倍,没有错误)

    Current stack is
    
    Pushing 1 onto stack:
    
    Current stack is
    1   
    
    Pushing 2 onto stack:
    
    Stack is FULL.Now doubling...
    
    Current stack is
    1   2   
    
    Pushing 3 onto stack:
    
    Current stack is
    1   2   3   
    
    Pushing 4 onto stack:
    
    Current stack is
    1   2   3   4   
    
    Pushing 5 onto stack:
    
    1   2   3   4   5   
    

3 个答案:

答案 0 :(得分:1)

我怀疑你可能会在某处覆盖你的缓冲区......并破坏堆。

检查您写入“堆栈”的代码。

另外:考虑使用Valgrind

答案 1 :(得分:1)

s->capacity存储堆栈中的项目数。每个项目的大小为sizeof(int)。第二个arg到realloc是字节的数量,就像malloc一样。

s->array=realloc(s->array,s->capacity);

你想要

s->array=realloc(s->array, s->capacity * sizeof(int));

或者更一般地说

s->array = realloc(s->array, s->capacity * sizeof(*(s->array)));

此外,您应该检查realloc的返回值并处理发生的任何错误。

这段代码是胡说八道:

s=realloc(s,(sizeof(struct stack)*2));//**UNCOMMENT THIS TO ELIMINATE ERROR**

首先,如果realloc决定移动您的数组,则不会将新的s返回给调用者。但更重要的是,您需要调整阵列的大小,而不是围绕它的元数据。只是巧合,取消注释该行隐藏了这个问题。

答案 2 :(得分:0)

至少,我的编译器会报告两个警告:

foo.c:40:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
foo.c:61:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^

第一个:

create()中,你永远不会真正返回新堆栈。这意味着您很快就会做一些未定义的行为。

第二个:

doublestack()中你永远不会返回任何东西,但你也永远不会尝试使用(错过的)返回值。但是,如果realloc成功,那么前一个指针现在可能是一个无效指针,这将导致未定义的行为。