Возврат указателя malloc - PullRequest
       8

Возврат указателя malloc

7 голосов
/ 31 марта 2011

Здесь довольно простой вопрос, я немного не уверен в том, что такое память в C.

Если у меня есть следующее

CGPoint* tileForCoordinates (CGPoint position, short width, short height)
{   
   CGPoint *tileCoordinate = (CGPoint*)malloc(sizeof(CGPoint));
   tileCoordinate->xTile = (position.xPosition / width);
   tileCoordinate->yTile = (position.yPosition / height);

   return tileCoordinate;
}

и я хотел бы вызвать это в другом исходном файле или где-то еще, объявил бы я указатель и выше и вернул бы его? Если это так, когда я звоню из другого класса, например

CGPoint *currentTilePosition = tileForCoordinates(curPosition, 50, 50);

Что происходит с указателем, возвращаемым malloc? Должен ли он быть освобожден или какова история? :)

Ответы [ 5 ]

6 голосов
/ 31 марта 2011

Чтобы ответить "что происходит с указателем, возвращенным функцией malloc ()?"

Указатель, объявленный malloc(), будет значением в кадре стека текущей выполняемой функции. Когда кадр стека (и, следовательно, *tileCoordinate) выходит из области видимости при возврате функции, этот указатель перестает существовать.

Однако, поскольку вы возвращаете значение указателя в вызывающую функцию, оно теперь существует в текущем кадре стека (после возврата). На это значение ссылается переменная *currentTilePosition.

Память , выделенная malloc() - это совершенно другая история; Динамически распределенная память существует в куче. Вы должны освободить любую память, выделенную в той же реализации, которая выполняет выделение. Это подразумевает вызов free() на currentTilePosition, как только вы закончите использовать его, обычно в том же файле.

4 голосов
/ 31 марта 2011

Можете ли вы передать tileCoordinate в качестве аргумента вызова функции?Таким образом, вызывающему абоненту будет легче запомнить malloc / calloc и free.

3 голосов
/ 31 марта 2011

Абоненту потребуется free указатель malloc, отредактированный вашей функцией.

Однако, если вы упакуете функцию tileForCoordinates в динамическую библиотеку, вы также должны предоставить сопутствующую функцию для освобождения памяти, а не для того, чтобы вызывающая сторона сделала это.Это связано с тем, что вызывающая сторона может ссылаться на среду выполнения C не так, как ваша библиотека.Например, если ваша библиотека статически связывается со средой выполнения C, а вызывающая сторона связывается с ней динамически, или наоборот, освобождение вызывающей памяти приводит к сбоям памяти.В таких случаях вы можете предоставить функцию, подобную следующей:

void freeTileCoordinates( CGPoint **tileCoordinate )
{
  // Also add additional checks for NULL pointer
  free( *tileCoordinate );
  *tileCoordinate = NULL;
}

Пример использования:

CGPoint *point = tileForCoordinates( ... );

// use point
...

// now free it
freeTileCoordinates( &point );
3 голосов
/ 31 марта 2011

Основное правило, которому нужно следовать, если вы возвращаете указатель * malloc * ed или даете пользователю функцию передать указатель обратно для освобождения или документ, который вы * malloc * редактировали, и что они должны его освободить.

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

1 голос
/ 31 марта 2011

Как правило, все, что вам malloc нужно, также free.Как еще одно правило, если ваш API выполняет распределение, ваш API также ДОЛЖЕН выполнять освобождение, поскольку в какой-то момент в будущем вы можете изменить базовый механизм.Кроме того, в Windows, если память выделяется библиотекой DLL, она должна быть освобождена той же самой библиотекой DLL, или происходит сбой.

Итак, в общем случае шаблон выглядит следующим образом:

MyType* foo = myapi_dosomething(x,y,z);
if (!foo) die("No Foo!");
use_object(foo);
myapi_free(foo);
foo=NULL; // just in case
...