Выделяете меньше места, чем необходимо для определенного типа? - PullRequest
5 голосов
/ 23 октября 2011

Я относительно новичок в программировании на C и с трудом понимаю всю проблему выделения памяти.

Допустим, я делаю:

int *n = malloc(sizeof(char));
// (assuming malloc doesn't return NULL of course)

Это обеспечивает указатель на int,но я не выделил достаточно памяти для int.Почему это работает тогда?Я мог бы даже привести его к int явно, и это не будет беспокоить gcc.Я знаю, что компиляторы C очень минималистичны, но даже если я присваиваю значение * n, которое не помещается в символ, например:

*n = 300;

... и распечатываю его потом:

printf("%d", *n);

... все работает отлично, хотя самое позднее я ожидаю какую-то ошибку, такую ​​как ошибка сегментации.

Я имею в виду, sizeof (char) равен 1, а sizeof(int) 4 на моей машине.Следовательно, 3 байта записываются в какое-то место в памяти, которое не было выделено должным образом.

Работает ли это только потому, что не покидает стек?

Может кто-нибудь указать мнеместо, где я мог бы найти просветление относительно этого материала?

Ответы [ 2 ]

7 голосов
/ 23 октября 2011

Это обеспечивает указатель на int, но я не выделил достаточно памяти для int.Почему это работает тогда?

Возвращаемое значение из malloc - void*, язык позволяет неявно преобразовывать его в любой тип указателя, в данном случае int*.Компиляторы обычно не включают в себя поведение, чтобы проверить, что то, что вы передали malloc, соответствует определенному требованию к размеру, в реальном коде это может быть очень сложно (когда непостоянные размеры, не известные во время компиляции, передаются в malloc).Как вы сказали, компилятор C обычно довольно минималистичен.Есть такие вещи, как инструменты «статического анализа», которые могут анализировать код, чтобы попытаться найти эти ошибки, но это совершенно другой класс инструментов, чем компилятор.

... все работает отлично, хотя самое позднее я ожидаю какую-то ошибку, такую ​​как ошибка сегментации.Я имею в виду, что sizeof (char) равен 1, а sizeof (int) равен 4 на моей машине.Следовательно, 3 байта записываются в какое-то место в памяти, которое не было выделено должным образом.

Запись за пределы выделенной памяти - это то, что называется «неопределенным поведением».Это означает, что совместимый компилятор может делать что угодно, когда это происходит.Иногда происходит сбой, иногда он может перезаписать какую-то другую переменную в вашей программе, иногда ничего не произойдет, а иногда ничего не будет казаться , и ваша программа потерпит крах позднее.

В данном конкретном случае происходит то, что большинство реализаций malloc выделяет минимум 16 байтов (или больше или меньше, например, 8 или 32), даже если вы запрашиваете меньше.Поэтому, когда вы перезаписываете свой выделенный байт, вы записываете в «лишнюю» память, которая ни для чего не использовалась. очень не рекомендуется использовать это поведение в любой реальной программе.

Работает ли это только потому, что не покидает стек?

Стек не имеет ничего общего с этой конкретной ситуацией.

Может ли кто-нибудь указать мне место, где я мог бы найти просветление относительно этого материала?

Любойхорошая книга C будет содержать информацию такого типа, посмотрите здесь: Руководство и список книг Definitive C

2 голосов
/ 23 октября 2011

Обычно 32-битная машина выделяет новую память на 32-битной границе - это ускоряет доступ к памяти.
Таким образом, он выделил байт, но следующие 3 байта не используются

Не надейся на это!

...