Что именно делают операции памяти malloc и free?

0

Недавно я встретил проблему с выпуском памяти. Во-первых, удар - это коды 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 для решения этих проблем. Не могли бы вы, ребята, дать мне какое-то профессиональное объяснение по этому поводу? Заранее спасибо.

  • 6
    Вы выделяете место для 5 предметов, но индексируете после окончания выделенной суммы. Это неопределенное поведение, и все может случиться.
  • 2
    Вы выходите за границы выделения со вторым циклом for. p [5] - это то, что находится в памяти в это время.
Показать ещё 1 комментарий
Теги:
gcc
visual-studio-2008

3 ответа

1

Это нормально, поскольку вы никогда не выделяли никаких данных в пространство памяти p [5]. Программа просто распечатает все данные, хранящиеся в этом пространстве.

1

Там нет детерминированного "объяснения по этому поводу". Запись данных на неизведанную территорию за выделенным пределом памяти вызывает неопределенное поведение. Поведение непредсказуемо. Это все, что есть.

По-прежнему странно видеть, что там напечатано 51. Обычно GCC также печатает 5 но с ошибкой с сообщением о повреждении памяти на free. Как вам удалось сделать этот код печати 51 не совсем ясным. Я сильно подозреваю, что код, который вы отправили, это не тот код, который вы использовали.

  • 0
    Код здесь именно то, что я бежал. Я знаю, что индекс находится вне диапазона. Я хочу знать, почему код раздавлен бесплатно. Откуда free знает, какой объем памяти должен быть освобожден?
  • 0
    malloc экономит объем памяти, выделенный по определенному адресу, поэтому free может освободить такое же количество. То, как malloc сохраняет это значение и любые проверки на наличие повреждений в выделенном блоке, зависит от реализации.
Показать ещё 1 комментарий
0

Кажется, у вас много вопросов, поэтому позвольте мне попытаться ответить на них отдельно:

  1. Как уже отмечалось выше, вы пишете за конец массива, поэтому, как только вы это сделали, вы находитесь на территории "неопределенного поведения", и это означает, что все может произойти, включая печать 5, 6 или 0xdeadbeaf, или взорвать ваш компьютер.

  2. В первом случае (VS2008) бесплатно появляется сообщение об ошибке на стандартном выходе. Для меня не очевидно, что это сообщение об ошибке, поэтому трудно объяснить, что происходит, но вы просите позже в комментарии о том, как VS2008 может знать размер выпускаемой вами памяти. Как правило, если вы выделяете память и сохраняете ее в указателе p, многие распределители памяти (malloc/free implementation) хранят в p [-1] размер выделенной памяти. На практике обычно также хранить по адресу p [p [-1]] специальное значение (скажем, 0xdeadbeaf). Эта "канарейка" проверяется бесплатно, чтобы увидеть, написано ли вы за концом массива. Подводя итог, ваш массив 5 * sizeof (int), вероятно, имеет длину не менее 5 * sizeof (int) + 2 * sizeof (char *), а распределитель памяти, используемый кодом, скомпилированным с VS2008, имеет довольно много проверок.

  3. В случае gcc, я нахожу удивительным, что вы получили 51 печатную версию. Если бы вы хотели исследовать wwhy, это точно, я бы рекомендовал получить дамп asm сгенерированного кода, а также запустить его под отладчиком, чтобы проверить, действительно ли 5 действительно написано за концом массива (gcc, возможно, решил не для генерации этого кода, поскольку он "неопределен"), и если это так, поместите точку наблюдения в эту ячейку памяти, чтобы увидеть, кто ее переопределяет, когда и почему.

  • 0
    Спасибо за подробный ответ. Я знал лучше о распределении памяти.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню