Переполнение стека С++

Это мой код. Когда я обращаюсь к массиву dtr в функции initImg, возникает исключение переполнения стека. В чем может быть причина?

#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;
}

person user570593    schedule 02.06.2011    source источник


Ответы (8)


Этот:

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

Каждый создает в стеке массив размером 4 * 1000 * 1000 ~ 4 МБ. Размер стека ограничен и обычно не превышает 4 МБ. Не делайте этого, создайте массивы в куче, используя new.

int *image = new int[W*H];
float *dtr = new float[W*H];
person Dr. Snoopy    schedule 02.06.2011
comment
@DeadMG: Зачем использовать динамическую структуру для статических данных? Если все, что он делает, это перебирает массив известного размера - используйте массив известного размера, поскольку он точно соответствует задаче. - person Simon; 03.06.2011
comment
@Simon: В любом случае вы создаете массив с динамическим размером, просто он имеет известный размер. Использование new напрямую приведет к утечке памяти и, среди прочего, имеет плохую/отсутствующую поддержку отладки для доступа за пределами границ. std::vector<int> image(W * H); выполняет ту же функцию гораздо более безопасным способом. - person Puppy; 03.06.2011
comment
@DeadMG: Как это массив с динамическим размером, если он не растет и не сжимается? Если подобный случай вызывает доступ за пределами границ или утечку памяти, вам определенно не следует использовать std::vector, потому что тогда вы не знаете, что делаете. Изучите основы, прежде чем использовать чужие решения. - person Simon; 03.06.2011
comment
Это массив с динамическим размером, поскольку память, в которой размещается массив, выделяется во время выполнения. Однако защита, на которую ссылается DeadMG, относительно дорогая и, по моему опыту, не такая уж и ценная. Если у вас есть фиксированное окно данных и вы хотите быстро его обработать, используйте новое/удаление самостоятельно или напишите/найдите класс-оболочку массива фиксированной длины для RAII-ness. - person Mark McKenna; 13.04.2012

Ваш стек, вероятно, недостаточно велик, чтобы вместить миллион целых чисел и миллион чисел с плавающей запятой (8 МБ). Поэтому, как только вы попытаетесь получить доступ за пределами размера стека, ваша операционная система выдаст вам ошибку. Объекты или массивы выше определенного размера должны быть размещены в куче — предпочтительно с использованием самоуправляемого класса самоконтроля границ, такого как std::vector — конкретный размер зависит от вашей реализации.

person Puppy    schedule 02.06.2011

В дополнение к переполнению стека у вас есть еще одна проблема, которая маскируется вашими определениями 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, вы переполните свои буферы.

Эта же проблема существует и в другом месте вашего примера кода.

person mah    schedule 02.06.2011

Вы создаете гигантские массивы в стеке. Просто используйте вместо этого std::vector:

std::vector<int> image(W*H);
std::vector<float> dtr(W*H);
person Mark B    schedule 02.06.2011

Ваш стек полон. Вы можете выделить память в куче или увеличить память стека. Насколько я знаю, максимальный размер составляет около 8 МБ, но это не очень хорошая идея. Лучшее решение — использовать выделение кучи или некоторые контейнеры (вектор), доступные в std.

person Adrian    schedule 25.09.2017

В конце концов вы доберетесь до

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

Что намного больше, чем вы выделили.

person Bo Persson    schedule 02.06.2011
comment
-1 Неверно, его цикл i < W, следовательно, i никогда не может быть W, чтобы получить W*W - person Dan F; 03.06.2011
comment
@Dan F - вы правы, однако комментарий Бо по-прежнему обнаруживает ошибку в коде плаката, которая замаскирована W == H. Если вместо этого W = 100 и H = 10, общий массив составляет 1000 элементов, но (i *W+j) = 9909, когда i==W-1 и j==H-1. Эта проблема возникает в любое время W>H, и это связано с тем, что циклы расположены в обратном порядке (или если оставить циклы такими, какие они есть, необходимо изменить расчет индекса). - person mah; 03.06.2011

Ваш компилятор определит размер стека. Способ обойти это — динамически выделить массивы с помощью std::vector array_one(W*H).

person Adrian Rodriguez    schedule 02.06.2011

Вы пытаетесь выделить память из стека. максимальная память, которая может быть выделена с использованием стека, зависит от компилятора. Поэтому попробуйте что-то подобное, чтобы избежать такого исключения.

#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 для выделения памяти из кучи...

person Anonymous    schedule 03.10.2012
comment
-1 Вопросу больше года, с принятым ответом, и вы ничего не добавляете, кроме того, что уже было в других ответах. Наконец, вы не исправили проблему с индексом, возникшую здесь в опубликованном вами коде. - person Massimiliano; 03.10.2012
comment
Я иду с @Massimiliano. Вам не нужно отвечать на уже принятый вопрос, если вы не можете предложить что-то новое. - person Rohit Vipin Mathews; 04.10.2012
comment
Eww malloc на C++ и без вкладок. - person Michal Štein; 20.05.2019