【问题标题】:(In C) Implementing stack using an array - Run-time error when doubling array size(在 C 中)使用数组实现堆栈 - 将数组大小加倍时出现运行时错误
【发布时间】:2014-10-02 13:45:57
【问题描述】:

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

我的问题:

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

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

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

  4. 我是不是在浪费内存?有没有更好的方法来使用数组来实现堆栈?

非常感谢您的宝贵时间。

代码和输出:(取消注释它说 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;
}

OUTPUT 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   

【问题讨论】:

  • 你应该用c标记这个。
  • 已编辑和标记。谢谢
  • 它可以是s-&gt;top = s-&gt;top + 1(s-&gt;top)++(括号可选)。不是s-&gt;top=s-&gt;top++

标签: c arrays stack double runtime-error


【解决方案1】:

s-&gt;capacity 存储堆栈中的项目数。每个项目的大小为sizeof(int)。 realloc 的第二个参数是 bytes 的数量,就像 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】:

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

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

另外:考虑使用Valgrind

【讨论】:

    【解决方案3】:

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

    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 成功了,那么之前的指针现在可能是一个无效的指针,这会导致未定义的行为。

    【讨论】:

    • 从 create() 返回新堆栈 - 已修复和编辑。但是除非我将堆栈加倍,否则相同的运行时错误仍然存​​在..
    • 这是正确的,如果您的 S 堆栈指针指向 create 返回的内容,那么您不知道它指向的位置,因为 create 不返回堆栈指针。由于您从不重新分配 S 它可以工作一段时间,但可能会不一致。请记住,当您像使用 create 和 doublestack 一样将指针传递给函数时,您只是将表示内存位置的数字复制到函数中,您实际上并没有对传入的指针做任何事情。
    • 从 doublestack() 返回双倍堆栈 - 我尝试将双倍堆栈返回给 s,但仍然出现相同的错误。将翻倍的堆栈返回到原始堆栈是否有问题?我需要在 push() 中完全创建一个新堆栈吗?我对 doublestack() 函数的更改是:添加最后一行 - “return s;”。我对 push() 函数的更改是:在 if() 构造中,更改行“doublestack(s);”到“s=doublestack(s);”
    猜你喜欢
    • 2021-12-03
    • 2017-02-17
    • 2015-02-14
    • 1970-01-01
    • 2010-12-15
    • 1970-01-01
    • 2022-07-07
    • 2010-11-26
    • 1970-01-01
    相关资源
    最近更新 更多