Недавно я встретил проблему с выпуском памяти. Во-первых, удар - это коды C:
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int *p =(int*) malloc(5*sizeof (int));
int i ;
for(i =0;i<5; i++)
p[i ]=i;
p[i ]=i;
for(i =0;i<6; i++)
printf("[%p]:%d\n" ,p+ i,p [i]);
free(p );
printf("The memory has been released.\n" );
}
По-видимому, проблема памяти выходит за пределы диапазона. И когда я использую компилятор VS2008, он дает следующий вывод и некоторые ошибки в выпуске памяти:
[00453E80]:0
[00453E84]:1
[00453E88]:2
[00453E8C]:3
[00453E90]:4
[00453E94]:5
Однако, когда я использую компилятор gcc 4.7.3 cygwin, я получаю следующий вывод:
[0x80028258]:0
[0x8002825c]:1
[0x80028260]:2
[0x80028264]:3
[0x80028268]:4
[0x8002826c]:51
The memory has been released.
По-видимому, коды работают нормально, но 5 не записывается в память. Таким образом, существуют некоторые различия между VS2008 и gcc для решения этих проблем. Не могли бы вы, ребята, дать мне какое-то профессиональное объяснение по этому поводу? Заранее спасибо.
Это нормально, поскольку вы никогда не выделяли никаких данных в пространство памяти p [5]. Программа просто распечатает все данные, хранящиеся в этом пространстве.
Там нет детерминированного "объяснения по этому поводу". Запись данных на неизведанную территорию за выделенным пределом памяти вызывает неопределенное поведение. Поведение непредсказуемо. Это все, что есть.
По-прежнему странно видеть, что там напечатано 51
. Обычно GCC также печатает 5
но с ошибкой с сообщением о повреждении памяти на free
. Как вам удалось сделать этот код печати 51
не совсем ясным. Я сильно подозреваю, что код, который вы отправили, это не тот код, который вы использовали.
malloc
экономит объем памяти, выделенный по определенному адресу, поэтому free
может освободить такое же количество. То, как malloc
сохраняет это значение и любые проверки на наличие повреждений в выделенном блоке, зависит от реализации.
Кажется, у вас много вопросов, поэтому позвольте мне попытаться ответить на них отдельно:
Как уже отмечалось выше, вы пишете за конец массива, поэтому, как только вы это сделали, вы находитесь на территории "неопределенного поведения", и это означает, что все может произойти, включая печать 5, 6 или 0xdeadbeaf, или взорвать ваш компьютер.
В первом случае (VS2008) бесплатно появляется сообщение об ошибке на стандартном выходе. Для меня не очевидно, что это сообщение об ошибке, поэтому трудно объяснить, что происходит, но вы просите позже в комментарии о том, как VS2008 может знать размер выпускаемой вами памяти. Как правило, если вы выделяете память и сохраняете ее в указателе p, многие распределители памяти (malloc/free implementation) хранят в p [-1] размер выделенной памяти. На практике обычно также хранить по адресу p [p [-1]] специальное значение (скажем, 0xdeadbeaf). Эта "канарейка" проверяется бесплатно, чтобы увидеть, написано ли вы за концом массива. Подводя итог, ваш массив 5 * sizeof (int), вероятно, имеет длину не менее 5 * sizeof (int) + 2 * sizeof (char *), а распределитель памяти, используемый кодом, скомпилированным с VS2008, имеет довольно много проверок.
В случае gcc, я нахожу удивительным, что вы получили 51 печатную версию. Если бы вы хотели исследовать wwhy, это точно, я бы рекомендовал получить дамп asm сгенерированного кода, а также запустить его под отладчиком, чтобы проверить, действительно ли 5 действительно написано за концом массива (gcc, возможно, решил не для генерации этого кода, поскольку он "неопределен"), и если это так, поместите точку наблюдения в эту ячейку памяти, чтобы увидеть, кто ее переопределяет, когда и почему.