Malloc - > сколько памяти было выделено?
# include <stdio.h>
# include <stdbool.h>
# include <string.h>
# include <stdlib.h>
int main ()
{
char * buffer;
buffer = malloc (2);
if (buffer == NULL){
printf("big errors");
}
strcpy(buffer, "hello");
printf("buffer is %sn", buffer);
free(buffer);
return 0;
}
Я выделил 2 байта памяти указателю / char buffer
но если я назначу строку C-style hello
к нему, он по-прежнему печатает всю строку, не давая мне никаких ошибок. Почему компилятор не дает мне ошибку, сообщая мне, что недостаточно выделенной памяти? Я прочитал пару вопросов, которые спрашивают, Как проверить, сколько памяти malloc
на самом деле выделяет, но я не нашел конкретного ответа. Не free
функция должна точно знать, сколько памяти выделено buffer
?
7 ответов
компилятор не знает. В этом радость и ужас К.--0--> принадлежит времени выполнения. Все компиляторы знают, что вы сказали ему, что он возвращает пустоту*, он понятия не имеет, сколько, или сколько strcpy
собирается копировать.
инструменты, такие как valgrind, обнаруживают некоторые из этих ошибок. Другие языки программирования затрудняют стрельбу в ногу. Не С.
нет производства malloc()
реализация должна помешать вам пытаться писать мимо того, что вы выделили. Предполагается, что если вы выделите 123 байта, вы будете использовать все или меньше того, что вы выделили. malloc()
, для эффективности, должен предположить, что программист собирается отслеживать их указатели.
использование памяти, которую вы явно и успешно не спрашивали malloc()
дать вам неопределенное поведение. Вы могли бы попросить n байт, но есть n + x, в силу malloc()
оптимизация реализации для выравнивания байтов. Или ты пишешь в черную дыру. Вы никогда не можете знать, вот почему это неопределенное поведение.
что было сказано ...
здесь malloc()
реализации, которые дают вам встроенный статистика и отладки, однако, они должны использоваться вместо стандартных malloc()
объект так же, как вы бы, если бы вы использовали мусор собранный сорт.
Я также видел варианты, разработанные строго для LD_PRELOAD, которые предоставляют функцию, позволяющую определить обратный вызов с хотя бы одним указателем void в качестве аргумента. Этот аргумент ожидает структуру, содержащую статистические данные. Другие инструменты, такие как электрический забор просто остановит вашу программу по точной инструкции, которая привела к переполнению или доступу к недопустимым блокам. Как @Р.. указывает в комментариях, что отлично подходит для отладка, но ужасно неэффективная.
честно говоря или (как говорится) "в конце дня" - гораздо проще использовать профилировщик кучи, такой как отчет и связанные с ней инструменты (массива) в этом случае, который даст вам достаточно информации. В этом конкретном случае Валгринд указал бы на очевидное - вы писали за выделенной границей. В большинстве случаев, однако, когда это не намеренно, хороший профайлер / детектор ошибок бесценен.
использование профилировщика не всегда возможно из-за:
- проблемы с синхронизацией во время работы под профилировщиком (но это обычные вызовы в любое время
malloc()
перехватываются). - профилировщик недоступен для вашей платформы / arch
- данные отладки (из журнала
malloc()
) должно быть неотъемлемой частью программы
мы использовали вариант библиотеки, которую я связал в HelenOS (я не конечно, если они все еще используют его) довольно долго, поскольку отладка на VMM, как известно, вызывает безумие.
тем не менее, подумайте о будущих последствиях при рассмотрении падения замены, когда дело доходит до malloc()
объект, вы почти всегда хотите использовать то, что система судов.
сколько malloc внутренне выделяет зависит от реализации и зависит от ОС (например, кратные 8 байтов или более). Запись в нераспределенные байты может привести к перезаписи значений других переменных, даже если компилятор и время выполнения не обнаружат ошибку. Функция free запоминает количество байтов, выделенных отдельно от выделенной области, например в свободном списке.
почему компилятор не дает мне ошибка, там достаточно выделена память ?
C
не блокирует использование памяти, которую вы не должны. Вы можете использовать эту память, но она плоха и приводит к неопределенному поведению. Вы пишете там, где не должны. Эта программа может выглядеть как работает правильно, но может позже сбой. Это UB
. ты не знаешь, что может случиться.
это то, что происходит с ваш strcpy()
. Вы пишете на месте, которое вам не принадлежит, но язык не защищает вас от этого. Поэтому вы должны быть уверены, что всегда знаете, что и где вы пишете, или убедитесь, что вы остановились, когда вы собираетесь превысить допустимые границы памяти.
я прочитал пару вопросов, которые задают как проверить, сколько памяти malloc на самом деле выделяет, но я не нашел конкретный ответ. Не "свободный" функция должна знать, сколько памяти точно выделяется "буфер"?
malloc()
может выделить больше памяти, чем вы запрашиваете причиной немного обивка.
еще:http://en.wikipedia.org/wiki/Data_structure_alignment
free()
free-s точно такая же сумма, которую вы выделили с malloc()
, но это не так умен, как вы думаете. Например:
int main()
{
char * ptr = malloc(10);
if(ptr)
{
++ptr; // Now on ptr+1
free(ptr); // Undefined Behaviour
}
}
вы всегда должны free()
указатель на первый блок. Делать free(0)
безопасно.
вы написали за конец буфера, который вы выделили. Результатом является неопределенное поведение. Некоторые библиотеки времени выполнения с правильными параметрами имеют хотя бы некоторую возможность диагностировать такие проблемы, но не все, и даже те, которые делают это только во время выполнения, и обычно только при компиляции с правильными параметрами.
Malloc - > сколько памяти было выделено?
при выделении памяти с помощью malloc. На успех он выделяет память и распределения по умолчанию 128К. первый вызов malloc дает 128К.
то, что вы просили buffer = malloc (2);
хотя вы запросили 2 байта. Он выделил 128k.
strcpy(buffer, "hello");
выделенный 128K кусок он начал обработку вашего запроса. "Привет"
строка может вписаться в это.
этот pgm сделает вас четкий.
int main()
{
int *p= (int *) malloc(2);---> request is only 2bytes
p[0]=100;
p[1]=200;
p[2]=300;
p[3]=400;
p[4]=500;
int i=0;
for (; ienter code here printf ("%d\t",*p);
}
на первый вызов malloc. Он выделяет 128k - - - > из того, что он обрабатывает ваш запрос (2 байта). Строка "hello" может поместиться в нее. Снова при втором звонке в malloc он обрабатывает ваш запрос от 128k.
за пределами 128k он использует интерфейс mmap. Вы можете обратиться к man-странице malloc.
нет независимого от компилятора / платформы способа узнать, сколько памяти фактически выделено malloc. malloc будет в целом выделения чуть больше, чем вы попросите его см. здесь:
http://41j.com/blog/2011/09/finding-out-how-much-memory-was-allocated/
в Linux вы можете использовать malloc_usable_size, чтобы узнать, сколько памяти вы можете использовать. На MacOS и других платформах BSD вы можете использовать malloc_size. Сообщение, связанное выше, имеет полные примеры обе эти техники.