LINUX.ORG.RU

Выделение памяти, ошибка сегментирования

 


0

2

Обясните мне, почему:
1.c:

#include <stdio.h>
int main() {
	int array[16000000];
	scanf("%d",&array[15999999]);
	return 0;
}

2.c:

#include <stdio.h>
int array[16000000];
int main() {
	scanf("%d",&array[15999999]);
	return 0;
}

3.c:

#include <stdio.h>
#include <stdlib.h>
int main() {
	int *array=malloc(16000000*sizeof(int));
	scanf("%d",&array[15999999]);
	free(array);
	return 0;
}

./1.c.out - ошибка сегментирования
./2.c.out - работает
./3.c.out - работает

Это баг или фича?

★★★★★

фича :)

anonymous
()

локальные переменные размещаются в стеке, а стек как правило ограничен (сильно зависит от реализации).

Ushenin
()

> Это баг или фича?

познаешь мир? похвально.

1.c — массив на стеке. дефолтный размер стека в линуксах^Wglibc — 8 метров.

arsi ★★★★★
()
Ответ на: комментарий от arsi

познаешь мир? похвально.

С удивлением обнаруживаю всё новые штуки в этом мире..

массив на стеке.

Хм.. Что такое стек в glibc?

Tanger ★★★★★
() автор топика
Ответ на: комментарий от Tanger

> Что такое стек в glibc?

не понял вопрос. ты не знаешь, что такое стек, что такое glibc, или почему именно glibc выделяет для тебя стек перед вызовом main?

arsi ★★★★★
()
Ответ на: комментарий от arsi

1.c — массив на стеке. дефолтный размер стека в линуксах^Wglibc — 8 метров.

он зависит от кол-во памяти хоста

mashina ★★★★★
()

Вот говорил я, что такие фичи C99, как динамические массивы, могут привести к попытке вот такого:

int array[16000000];

Лучше пользуйся только alloc'ом.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от arsi

Путем несложного теста я выяснил, что у меня, например, размер стека равен 8375059 байт.

Пример:

cat 1.c 
#include <stdio.h>
#include <stdint.h>
int main(int argc, char **argv){
	for(int i = 8375000; i ++;){
		printf("i=%d : ", i);
		uint8_t arr[i];
		arr[i-1] = 4;
		printf("%d\n", arr[i-1]);
	}
	return 0;
}

gcc 1.c  -std=gnu99 -Wall -Werror

./a.out

…
i=8375055 : 4
i=8375056 : 4
Ошибка сегментирования (core dumped)

Eddy_Em ☆☆☆☆☆
()
Последнее исправление: Eddy_Em (всего исправлений: 1)
Ответ на: комментарий от Eddy_Em

путём `ulimit -s` ты мог бы выяснить, какой у тебя размер стека, но ты не поленился и написал какой-то быдлокод, что тоже похвально ;)

arsi ★★★★★
()
Ответ на: комментарий от Tanger

Потому что все автоматические переменные в стек попадают.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Tanger

> Нет. скорее я не понимаю, почему в стеке находится массив, а не указатель на него..

ясно. пичалька. учи матчасть, что я ещё тебе могу сказать…

arsi ★★★★★
()
Ответ на: комментарий от Tanger

> Ссылки на нужные куски документации.

…сам найдёшь в гугле.

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

arsi ★★★★★
()
int main() {
	int array[16000000];
	scanf("%d",&array[15999999]);
	return 0;
}

Офигительный у тебя стек, а?

mr_doug
()
Ответ на: комментарий от Tanger

почему в стеке находится массив, а не указатель на него..

Потому что int array[16000000] имеет тип массива, а не указателя на него. Ваш К.О.

no-such-file ★★★★★
()

Все локальные нестатичные переменные в си размещаются на стеке программы (в нормальных реализациях).

Если хочешь понять эту кухню - стоит познакомиться с ассемблером.

unsigned ★★★★
()

Для затравки: http://stackoverflow.com/questions/5258724/stack-variables-vs-heap-variables

А вообще C достаточно сложная вещь, не надо его учить «на 20%». Потому что иначе твой код из-за обилия багов будет бесполезен. Если вообще будет работать.

Так же тебе понадобятся valgrind и gdb. Все программы прогоняй через valgrind, даже если кажется что всё работает.

true_admin ★★★★★
()
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        subq    $64000000, %rsp ;<= эта строка самая забавная! обкуренная и прикольная! да ещё и бухая в догонку. ягой убилась.
        movl    $.LC0, %eax
        leaq    -64000000(%rbp), %rdx
        addq    $63999996, %rdx
        movq    %rdx, %rsi
        movq    %rax, %rdi
        movl    $0, %eax
        call    __isoc99_scanf
        movl    $0, %eax
        leave
        ret
        .cfi_endproc
nanoolinux ★★★★
()

Вопрос в этом топике может и не совсем в тему, но перекликается. Может заодно просветите неуча. Когда в проге выполняется free(), то я, так понимаю, непосредственно освобождение памяти может быть отложено до некоторого более удобного с точки зрения минимизации накладных расходов момента времени? Это так?

zloy_starper ★★★
()
Ответ на: комментарий от zloy_starper

поведение, которое ты описал характерно как раз для malloc. а вот для free думаю зависит от аллокатора.

nanoolinux ★★★★
()
Последнее исправление: nanoolinux (всего исправлений: 1)
Ответ на: комментарий от zloy_starper

Когда в проге выполняется free(), то я, так понимаю, непосредственно освобождение памяти может быть отложено до некоторого более удобного с точки зрения минимизации накладных расходов момента времени? Это так?

а что ты называешь «освобождение памяти»? Записать куда-то «эта память пуста»? Тогда да. Стереть? Тогда нет.

drBatty ★★
()
Ответ на: комментарий от Tanger

указатель тоже там находится, но у вас указатель присутствует только в 3-м примере.

массив мог бы находиться не в стеке, но вы его объявили в стеке, вот он там и находится.

IvanR ★★★
()
Ответ на: комментарий от drBatty

а что ты называешь «освобождение памяти»? Записать куда-то «эта память пуста»? Тогда да. Стереть? Тогда нет.

Разумеется после free по соответствующему физическому адресу останутся те же данные, что там там были ранее. Но когда-то память должна быть «отдана» процессом, иначе была бы бесконечная утечка памяти. И тогда обращение к данному адресу должно привести к segmentation fault. Просто столкнулся с собственной ошибкой в коде. В одном месте выполняется освобождение памяти, ранее выделенной под структуру, а затем идет обращение к данным этой структуры.При этом не только не происходит краха процесса, но выполняется все корректно.

zloy_starper ★★★
()
Ответ на: комментарий от zloy_starper

Разумеется после free по соответствующему физическому адресу останутся те же данные, что там там были ранее. Но когда-то память должна быть «отдана» процессом, иначе была бы бесконечная утечка памяти. И тогда обращение к данному адресу должно привести к segmentation fault.

ну рассчитывай на худшее - что аллокатор СРАЗУ делает эту память свободной, и следующий же malloc() её _может_ выделить (IRL часто так и бывает, ибо модель FIFO весьма популярна. В стеке это работает _всегда_)

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

что-бы ловить такой _быдлокод_, можно сделать обёртку над free(), которая не только освобождает память, но и чем-то её забивает. Такие обёртки используются например в MSVC, что-бы быдлокодеры поменьше быдлокода писали.

Ну а по стандарту, ЕМНИП тут имеем UB - может всё умрёт, может диск форматнётся, а может будет работать. А может будет работать сейчас, а завтра будет восстание БЧР.

drBatty ★★
()
Ответ на: комментарий от Tanger

1. ioccc.org

2. K&R A 8.1 Спецификаторы класса памяти - последний абзац - про авто auto.

3. зачем портить себя знанием С если тебе уже ортодоксно , что составные сущности(массивы в том числе) обязаны быть в куче - кури C#/Java и тебе и народному хозяйству арканзайщины будеть пользы много больше.

qulinxao ★★☆
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.