Я хочу понять malloc() и realloc() в C

Возможный дубликат:
Запись в указатель за пределами границ после malloc() не вызывает ошибки

Я пытаюсь использовать очень простую программу для выделения памяти для массива всего из 2 ints. Я выделяю память только для 2 ints, то есть array[0] и array[1]: почему можно использовать array[2] и он хорошо работает?

#include <stdio.h>

int main(int argc, char *argv[])
{
    int *array;
    int i;
    array = NULL;
    array = malloc(sizeof(int)*2);

    array[0] = 2;
    array[1] = 3;
    array[2] = 4;

    for( i = 0; i<3 ; i++)
    printf("%d\n", array[i]);

    return 0;
}

Вывод:

 2
 3
 4

person hina abbasi    schedule 16.08.2012    source источник


Ответы (6)


Это может казаться эффективным, потому что C не препятствует доступу к памяти, которая вам не принадлежит. Даже если кажется, что он работает, код все равно неверен и может не сработать завтра. Вы вызываете неопределенное поведение, записывая/читая память, которая вам не принадлежит.

person pb2q    schedule 16.08.2012

Прочтите ответы здесь, чтобы лучше понимание

По сути, это повреждение памяти, как описано здесь

Попробуйте использовать очень большое число вместо 4, и это приведет к ошибке, потому что при вызове malloc() для вас вырезается небольшой кусок памяти из большей страницы. Таким образом, написание за пределами вашего фрагмента не обязательно означает, что вы потерпите крах. В массиве [4] вы не пишете за пределами страницы, выделенной для этого начального фрагмента, поэтому технически вы пишете на действительный сопоставленный адрес. Источник

person kitwalker    schedule 16.08.2012

pb2q абсолютно правильно. Один из способов проверить, что вы обращаетесь к нераспределенной памяти, — это сделать следующее:

array = calloc(sizeof(int) * 2); 
for (i = 0; i < 3; i++)
    printf("%d\n", array[i]);

Вероятно, вы получите следующий вывод:

0
0
*random value*
person laker    schedule 16.08.2012
comment
Есть ли какая-нибудь функция, для которой я мог бы указать свое «значение сигнала», чтобы заполнить кусок памяти? - person parallelgeek; 16.08.2012

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

Когда вы создаете массив, вы получаете указатель на адрес в памяти и можете использовать его по своему усмотрению. Выделяя память, вы предотвращаете создание других объектов в этом фрагменте памяти, как если бы вы зарезервировали его для своего массива. Тем не менее, нет ограничений на превышение этой суммы, и вы можете читать и писать куда угодно. Преимущество этого в том, что у вас есть довольно много возможностей и вы можете напрямую манипулировать адресами. Недостатком является то, что вы можете очень легко заставить вашу программу развалиться, если я манипулирую информацией в ячейках памяти, принадлежащих другим объектам.

Из этого следует вынести то, что C дает вам большое количество мощности и оставляет использование этой мощности полностью на ваше усмотрение.

person HypnoticSheep    schedule 16.08.2012

Я считаю, что это работает, потому что ваша реализация malloc помещает некоторую информацию до и после блока памяти и, возможно, распределяет по блокам (например, округляет запрос на выделение до ближайших 64 байтов). malloced память должна иметь возможность освобождаться, а для этого требуется некоторая информация о ее размере и так далее, эта информация помещается непосредственно перед и/или после выделенной памяти.

Если данные распределены по частям, то будет некоторый предел, которого вы можете достичь, когда вы полностью заполните один «блок», а чтение array[n] будет за пределами конца «блока». Мы можем проверить это следующим образом:

int main() {
    int i;
    char * a;
    for (i = 1; i < 10000; i++) {
        a = malloc(i);
        a[i] = 'x';
        printf("%d %c\n", i, a[i]);
        free(a);
    }
    return 0;
}

Он mallocсоздает все более крупные блоки памяти и проверяет наличие сегментных ошибок, выходящих за пределы допустимого диапазона. Усеченный вывод, который я получаю:

1 x
[...]
58 x
59 x
60 x
61 x
62 x
*** glibc detected *** ./a.out: free(): invalid next size (normal): 0x0a041008 ***
[...]

т.е. попытка сделать a = malloc(63); a[63] = 'x'; терпит неудачу, потому что это искажает метаданные, о которых я говорил ранее.

person huon    schedule 16.08.2012

вот совет: вы должны избегать использования printf в функциях... используйте его только внутри main() (:

когда вы используете malloc и realloc, C будет выделять память с размером int. Он не будет выделять другое «место» для ввода номера. Единственное, что происходит, это если данные, которые вы помещаете, имеют тот же размер байта, что и int. Это то, что обычно происходит, потому что C не сообщит вам, заполнен ли размер массива. Будьте осторожны с этим.

person João Victor    schedule 16.08.2012