Получение исключения переполнения стека при объявлении большого массива

Следующий код генерирует для меня ошибку переполнения стека.

int main(int argc, char* argv[])
{
    int sieve[2000000];
    return 0;
}

Как мне обойти это? Я использую Turbo C ++, но хочу сохранить свой код на C

РЕДАКТИРОВАТЬ:

Спасибо за совет. Приведенный выше код был только для примера, я фактически объявляю массив в функции, а не в sub main. Кроме того, мне нужно было, чтобы массив был инициализирован нулями, поэтому, когда я погуглил malloc, я обнаружил, что calloc идеально подходит для моих целей.

Malloc / calloc также имеет преимущество перед распределением в стеке, позволяя мне объявлять размер с помощью переменной.


person Patrick McDonald    schedule 21.02.2009    source источник
comment
Я прочитал исключение переполнения стека и подумал про себя ...? что-то не так с сайтом? Ясно, что я провожу здесь слишком много времени: - /   -  person David Z    schedule 21.02.2009
comment
Я почти уверен, что этот тип вопросов должен был возникать ранее на этом сайте, но поиск переполнения стека вообще бесполезен   -  person Patrick McDonald    schedule 21.02.2009
comment
Я думаю, что каждый программист на C в конечном итоге тратит много времени на решение этой проблемы впервые ..   -  person MahlerFive    schedule 21.02.2009
comment
Turbo C ++ - это 16-разрядное приложение, что означает, что оно использует сегментацию памяти, каждый сегмент имеет размер 64 КБ, поэтому никакая структура не может быть больше этого числа, а общее использование памяти максимально равно 640 КБ (1 МБ или более с некоторым расширенным диспетчером памяти. ). Зачем вам нужен компилятор, которому более 20 лет?   -  person phuclv    schedule 28.10.2013
comment
В то время мне просто нужен был бесплатный компилятор C для Windows, и он, казалось, компилировал примеры, которые я пробовал, из книги 25-летней давности. Какой бесплатный компилятор вы бы порекомендовали сейчас?   -  person Patrick McDonald    schedule 29.10.2013
comment
@MahlerFive, ты дал мне надежду!   -  person hat    schedule 30.05.2018
comment
К настоящему времени, надеюсь, вы открыли для себя GCC. Среди прочего, он поставляется в комплекте с Code :: Blocks IDE. .   -  person ryyker    schedule 21.08.2019


Ответы (8)


Ваш массив слишком велик, чтобы поместиться в стек, подумайте об использовании кучи:

int *sieve = malloc(2000000 * sizeof(*sieve));

Если вы действительно хотите изменить размер стека, посмотрите в этом документе.

Совет: - Не забывайте освобождать динамически выделяемую память, когда она больше не нужна.

person arul    schedule 21.02.2009
comment
Поскольку это C, вам не нужно (да и не следует) приводить возвращаемое значение malloc. - person aib; 23.02.2009
comment
Почему бы вам не использовать результат malloc? Разве вам не пришлось бы использовать его из void *, чтобы что-нибудь с ним сделать? - person ; 27.02.2009
comment
@ yodaj007: вам не нужно явно приводить его. Поскольку назначенная переменная также имеет тип указателя, присвоение выполняет неявное преобразование. - person jweyrich; 10.02.2011
comment
@Amy Прочтите это: Я использую результат malloc ?. Это объясняет несколько причин, по которым нельзя приводить malloc (или любые другие функции выделения памяти) в C. - person WhozCraig; 26.08.2015

Есть 3 способа:

  1. Выделить массив в куче - используйте malloc(), как предлагали другие плакаты. Не забудьте free() это сделать (хотя для main() это не так важно - ОС очистит память за вас при завершении программы).
  2. Объявите массив на уровне единицы - он будет размещен в сегменте данных и виден всем (добавление static в объявление ограничит видимость единицей).
  3. Объявите свой массив как static - в этом случае он будет размещен в сегменте данных, но виден только в main().
person qrdl    schedule 21.02.2009
comment
Я бы просто сделал его статичным: main() следует вызывать только один раз, так что здесь нет подводных камней; здесь не нужно malloc() ... - person Christoph; 21.02.2009

Лучше разместить его в куче, а не в стеке. что-то типа

int main(int argc, char* argv[])
{
    int * sieve;
    sieve = malloc(20000);
    return 0;
}
person Cogsy    schedule 21.02.2009
comment
И проверьте сито на NULL - person paulm; 12.05.2014
comment
Я только сито для тебя - Зохан - person DragonLord; 30.07.2015
comment
Я думаю, вы имели в виду sieve = malloc(20000 * sizeof *sieve) - если ваша платформа не имеет int размера 1 (и даже тогда я бы не стал вставлять это предположение в код). - person Toby Speight; 16.05.2018

Это около 7 МБ стека. В Visual Studio вы должны использовать / STACK: ###, ###, чтобы отразить желаемый размер. Если вам действительно нужен огромный стек (может быть хорошей причиной, используя LISP или что-то в этом роде :), даже куча ограничена небольшими выделениями, прежде чем заставлять вас использовать VirtualAlloc), вы также можете настроить свой PE для сборки с / LARGEADDRESSAAWARE (снова компоновщик Visual Studio), но эта настройка является вашим заголовком PE, чтобы ваш скомпилированный двоичный файл мог адресовать полные 4 ГБ 32-битного адресного пространства (при работе в WOW64). Если вы создаете действительно массивные двоичные файлы, вам также обычно потребуется настроить / bigobj в качестве дополнительного параметра компоновщика.

И если вам все еще нужно больше места, вы можете радикально нарушить соглашение, используя что-то похожее на (снова ссылка MSVC) / merge :, что позволит вам упаковать один раздел в другой, чтобы вы могли использовать каждый байт для одного общего кода. / раздел данных. Естественно, вам также потребуется настроить разрешения SECTIONS в файле def или с помощью #pgrama.

person RandomNickName42    schedule 21.02.2009

Используйте malloc. Все проверяют, что тип возвращаемого значения не равен нулю, если он равен нулю, значит, вашей системе просто не хватает памяти для размещения такого количества значений.

person Community    schedule 22.02.2009

Есть ли причина, по которой вы не можете использовать alloca () для выделения необходимого места в кадре стека в зависимости от того, насколько большим действительно должен быть объект?

Если вы это сделаете, но по-прежнему переборщите стек, поместите его в выделенную кучу. Я настоятельно рекомендую НЕ объявлять его статическим в main () и помещать его в сегмент данных.

Если он действительно должен быть таким большим, и ваша программа не может выделить его в куче, ваша программа действительно не имеет никакого отношения к работе на этом типе машины с самого начала.

Чего (именно) вы пытаетесь достичь?

person Tim Post♦    schedule 21.02.2009
comment
Я использую задачи из ProjectEuler.net для изучения C и реализую алгоритм Сито Эратосфена, поэтому он должен быть таким большим. malloc отлично подходит для моих целей, хотя - person Patrick McDonald; 21.02.2009

Ваш массив огромен.

Возможно, ваша машина или ОС не имеют или не хотят выделять столько памяти.


Если вам абсолютно необходим огромный массив, вы можете попытаться выделить его динамически (используя malloc(...)), но тогда вы рискуете потерять память. Не забудьте освободить память.

Преимущество malloc в том, что он пытается выделить память в куче, а не в стеке (поэтому вы не получите переполнения стека).

Вы можете проверить значение, которое возвращает malloc, чтобы узнать, было ли выделение успешным или неудачным. Если это не удается, просто попробуйте выделить меньший массив.


Другой вариант - использовать другую структуру данных, размер которой можно изменять на лету (например, связанный список). Насколько хорош этот вариант, зависит от того, что вы собираетесь делать с данными.

Еще один вариант - хранить данные в файле с потоковой передачей данных на лету. Этот подход самый медленный.

Если вы выберете хранилище на жестком диске, вы также можете использовать существующую библиотеку (для баз данных).

person Ivan Rubinson    schedule 04.07.2016

Поскольку Turbo C / C ++ - это 16-битный компилятор, тип данных int занимает около 2 байтов. 2 байта * 2000000 = 4000000 байтов = 3,8147 МБ пространства.

Автоматические переменные функции хранятся в стеке, и это вызвало переполнение памяти стека. Вместо этого используйте память данных [используя статическую или глобальную переменную] или динамическую память кучи [используя malloc / calloc] для создания необходимой памяти в соответствии с доступностью отображения памяти процессора.

person Arun Chettoor    schedule 13.07.2017