2017-01-24 4 views
1

Мне было интересно в последнее время о поведении функции malloc в C, и я наблюдал интересное поведение. Это похоже на первое значение «вне границ» после того, как malloc окажется NULL (или, по крайней мере, возвращает что-то, что считается ложным, на if). Вот иллюстрация:Поведение malloc: первое значение «вне границ» всегда равно NULL/0?

int main(){ 

    int i; 
    double * d_ptr = malloc (10 * sizeof (double)); //malloc 10 double 
    for (i=0 ; i<10 ; i++){       // initialise them ... 
     d_ptr[i] = 42; 
    } 

    for (i=0 ;i <50 ; i++){ /// loop obviously trying to go out of bounds 
     if (d_ptr[i]){ 
      printf("i=%d,d[%d]=%f\n",i,i,d_ptr[i]); 
     } 
     else { 
      printf("out of bounds : i=%d\n",i); 
      break; 
     } 
    } 

    printf("exited 'out of bounds loop' safely\n"); 
    free(d_ptr); 
    return 0; 
} 

Вот результат:

i=0,d[0]=42.000000 
i=1,d[1]=42.000000 
i=2,d[2]=42.000000 
i=3,d[3]=42.000000 
i=4,d[4]=42.000000 
i=5,d[5]=42.000000 
i=6,d[6]=42.000000 
i=7,d[7]=42.000000 
i=8,d[8]=42.000000 
i=9,d[9]=42.000000 
out of bounds : i=10 
exited 'out of bounds loop' safely 

Мои вопросы:

  • Является ли это поведение предсказуемым? Я попробовал кучу переменных типов, разных размеров для malloc, и я всегда покидаю цикл безопасно.

  • Если она предсказуема, она может стать надежным способом петли на указатели в ситуации, когда зная их «размер» будет сложно, или требует много переписывания?

  • И, наконец, каково его более глубокое объяснение? делает malloc выделяет одно слово дополнительно после того, как пространство памяти было запрошено до выделить?
+3

Выход за пределы - это неопределенное поведение. Все может случиться, это определенно не предсказуемо. – Barmar

+0

Попробуйте освободить память после того, как вы присвоили ей, затем выделите немного меньший блок и посмотрите, все ли вы получаете '0' в конце нового блока. – Barmar

ответ

2

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

Запуск этой программы под Valgrind дал следующие результаты:

==22701== Memcheck, a memory error detector 
==22701== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. 
==22701== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info 
==22701== Command: /tmp/x1 
==22701== 
i=0,d[0]=42.000000 
i=1,d[1]=42.000000 
i=2,d[2]=42.000000 
i=3,d[3]=42.000000 
i=4,d[4]=42.000000 
i=5,d[5]=42.000000 
i=6,d[6]=42.000000 
i=7,d[7]=42.000000 
i=8,d[8]=42.000000 
i=9,d[9]=42.000000 
==22701== Invalid read of size 8 
==22701== at 0x4005C4: main (x1.c:13) 
==22701== Address 0x4c18090 is 0 bytes after a block of size 80 alloc'd 
==22701== at 0x4A0610C: malloc (vg_replace_malloc.c:195) 
==22701== by 0x400579: main (x1.c:7) 
==22701== 
out of bounds : i=10 
exited 'out of bounds loop' safely 
==22701== 
==22701== HEAP SUMMARY: 
==22701==  in use at exit: 0 bytes in 0 blocks 
==22701== total heap usage: 1 allocs, 1 frees, 80 bytes allocated 
==22701== 
==22701== All heap blocks were freed -- no leaks are possible 
==22701== 
==22701== For counts of detected and suppressed errors, rerun with: -v 
==22701== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4) 

Как вы можете видеть, это был распознан как чтение мимо конца malloc'ed буфера.

Просто потому, что программа может потерпеть крах, это не значит, что она будет.

Так нет, это поведение не предсказуемо.

2

«Является ли это поведение предсказуемым?» Нет, это undefined. «И, наконец, какое более глубокое объяснение? Malloc выделяет одно слово дополнительно после того, как пространство памяти было предложено выделить?» Нет, по крайней мере, не в какой-либо реализации, о которой я знаю, вы никогда не должны сознательно пытаться получить доступ к массиву за пределами границ или разыменовать неинициализированные данные, поскольку это всегда приведет к неопределенному поведению. В некоторых случаях вам может повезти с UB, и программа будет вести себя так, как ожидалось, даже после того, как она была вызвана, просто остерегайтесь time travelling nasal dragons.

+0

Спасибо и за советы, и за время путешествия носовых драконов! Иногда ничего лучше, чем хороший образ, чтобы запомнить холодный факт. –