堆栈溢出 C++

10

这是我的代码。当我在initImg函数中访问dtr数组时,会出现堆栈溢出异常。可能的原因是什么?

#define W 1000
#define H 1000
#define MAX 100000 
void initImg(int img[], float dtr[])
{
    for(int i=0;i<W;i++)
        for(int j=0;j<H;j++)
            img[i*W+j]=255;

    for(int j=0;j<H;j++)
    {
        img[j] = 0;
        img[W*(W-1)+j] = 0;
    }
    for(int i=0;i<W;i++)
    {
        img[i*W] = 0;
        img[i*W+H-1] = 0;
    }
    for(int i=0;i<W;i++)
        for(int j=0;j<H;j++)
        { 
            if(img[i*W+j]==0)
                dtr[i*W+j] = 0;    // <------here
            else
                dtr[i*W+j] = MAX;  // <------here
        }
}
int main()
{
    int image[W*H];
    float dtr[W*H];
    initImg(image,dtr);
    return 0;
}
8个回答

20

这个:

int image[W*H];
float dtr[W*H];

在栈上创建了一个大小为4 * 1000 * 1000 ~ 4 MB的数组。栈空间是有限的,通常小于4MB。不要这样做,在堆中使用new创建数组。

int *image = new int[W*H];
float *dtr = new float[W*H];

@DeadMG:为什么要为静态数据使用动态结构?如果他所做的只是迭代一个已知大小的数组-使用已知大小的数组,因为它完全适合这个问题。 - Simon
5
@Simon:无论如何,您都在创建一个动态大小的数组,只是其大小已知。直接使用new操作符可能会导致内存泄漏,并且对于越界访问具有较差或根本没有调试支持,等等。std::vector<int> image(W * H);以极为安全的方式执行相同的功能。 - Puppy
@DeadMG: 如果一个动态大小的数组不会增长或缩小,那它怎么算是动态大小的呢?如果这种情况可能造成越界访问或内存泄漏,你绝对不应该使用std::vector,因为那样你就不知道自己在做什么。在使用别人的解决方案之前,先学习基础知识。 - Simon
它是一个动态大小的数组,因为托管数组的内存是在运行时分配的。然而,DeadMG所提到的保护措施相对昂贵,在我的经验中并不那么有价值。如果您有一个固定的数据窗口,并且想要快速处理它,请自己使用new/delete,或编写/查找一个固定长度的数组包装类以实现RAII。 - Mark McKenna

11

你的堆栈可能不足以容纳一百万个整数和一百万个浮点数(8MB)。因此,一旦尝试访问超出堆栈大小的内容,操作系统会抛出错误。特定大小的对象或数组需要在堆上分配 - 最好使用一个自管理、自边界检查的类,例如std::vector - 具体大小取决于你的实现。


4
除了堆栈溢出之外,您还有另一个问题——这个问题被您对W和H的定义掩盖了。
for(int i=0;i<W;i++)
    for(int j=0;j<H;j++)
    { 
        if(img[i*W+j]==0)
            dtr[i*W+j] = 0;    // <------here
        else
            dtr[i*W+j] = MAX;  // <------here
    }

你的 i 循环应该从 0 到 H-1,而不是 W-1(j 循环也应该交换)。否则,如果 W==H,则你的代码只能在这种情况下正确运行。如果 WH,则会超出缓冲区。
你的代码示例中还存在同样的问题。

2

您正在堆栈上创建巨大的数组。只需使用std::vector即可:

std::vector<int> image(W*H);
std::vector<float> dtr(W*H);

1

你的栈已满。你可以在堆中分配内存或增加栈内存。据我所知,最大大小约为8MB,但这不是一个很好的想法。最好的解决方案是使用堆分配或一些std中可用的容器(例如vector)。


0

编译器会定义堆栈大小。解决该问题的一种方法是使用std::vector array_one(W*H)动态分配数组。


0

你最终会到达

dtr[W*W+j] = 0;   <------here

这比你分配的要多得多。


-1 是错误的,他的循环是 i < W,因此 i 永远不可能等于 W 以得到 W*W - Dan F
@Dan F - 你说得对,但Bo的评论仍然揭示了海报代码中的一个错误——这个错误被W == H掩盖了。如果改为W = 100和H = 10,则总数组有1000个元素,但当i==W-1且j==H-1时,(i*W+j) = 9909。每当W>H时就会出现这个问题,这是因为循环是反向的(或者保持循环不变,需要改变索引计算)。 - mah

-4

你正在尝试从堆栈中分配内存。使用堆栈可以分配的最大内存取决于编译器。 因此,尝试像这样做以避免此类异常。

#include <stdlib.h>
#define W 1000
#define H 1000 
#define MAX 100000 
void initImg(int img[], float dtr[]) 
{ 
for(int i=0;i<W;i++) 
for(int j=0;j<H;j++) 
img[i*W+j]=255; 

for(int j=0;j<H;j++) 
{ 
img[j] = 0; 
img[W*(W-1)+j] = 0; 
} 
for(int i=0;i<W;i++) 
{ 
img[i*W] = 0; 
img[i*W+H-1] = 0; 
} 
for(int i=0;i<W;i++) 
for(int j=0;j<H;j++) 
{ 
if(img[i*W+j]==0) 
dtr[i*W+j] = 0; // <------here 
else 
dtr[i*W+j] = MAX; // <------here 
} 
} 
int main() 
{ 
int *image = (int*)malloc(4*W*H);   //Malloc the memory....(Allocated from Heap..)
float *dtr = (float*)malloc(4*W*H);

if(image && dtr) //If none of the ptr is NULL. Means memory is allocated...
{
initImg(image,dtr); 
}
return 0; 
}

你可以使用new来分配堆内存,而不是使用malloc...


这个问题已经超过一年了,有一个被接受的答案,而你除了其他答案中已经提到的内容之外没有添加任何东西。最后,你也没有纠正你发布的代码中所提出的索引问题 在此处 - Massimiliano
我跟随@Massimiliano。除非你有新的建议,否则不需要回答已经被接受的问题。 - Rohit Vipin Mathews
C++中的malloc太丑了,而且没有制表符。 - DexterHaxxor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接