malloc и область действия - PullRequest
       3

malloc и область действия

1 голос
/ 12 ноября 2011

Я изо всех сил пытаюсь обернуть голову вокруг malloc в c - особенно, когда он должен быть свободным () 'd.Я получаю странные ошибки в gcc, такие как:

... free(): invalid next size (fast): ...

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

FILE *f = fopen(file,"r");
char x[256];
while(1) {
    if(fgets(x,sizeof x,f)==NULL) break;
    char *tmp = some_function_return_char_pointer(x); //OR malloc(nbytes);
    // do some stuff
    free(tmp); // this is where I get the error, but only sometimes
}

Я проверил очевидные вещи, например, если x равен NULL, но это не так;он просто падает на случайных строках.

Но мой РЕАЛЬНЫЙ вопрос - когда мне нужно использовать free () ?Или, возможно, более правильно, когда я не должен использовать бесплатно?Что если malloc находится в функции, и я возвращаю переменную, которая использовала malloc ()?Как насчет цикла for или while?Имеет ли malloc-ing для массива struct те же правила, что и для указателя строки / символа?

Я получаю из ошибок, которые я получаю в gcc при сбое программы, что я просто не понимаю malloc исвободно.Я провел свое качественное время с Google, и я все еще бью кирпичные стены.Есть ли хорошие ресурсы, которые вы нашли?Все, что я вижу, говорит о том, что всякий раз, когда я использую malloc, мне нужно использовать free.Но потом я пытаюсь это сделать, и моя программа падает.Так что, может быть, это отличается в зависимости от области видимости переменной?Освобождает ли C память в конце цикла, когда внутри нее объявлена ​​переменная?В конце функции?

Итак:

for(i=0;i<100;i++) char *x=malloc(n); // no need to use free(x)?

но:

char *x;
for(i=0;i<100;i++) {
    x=malloc(n);
    free(x); //must do this, since scope of x greater than loop?
}

Это правильно?

Надеюсь, я делаючувство ...

Ответы [ 7 ]

5 голосов
/ 12 ноября 2011

malloc() - это динамический распределитель C .Вы должны понимать разницу между автоматическими (объемными) и динамическими (ручными) переменными.

Автоматические переменные действуют в течение всего срока их действия.Это те, которые вы объявляете без какого-либо украшения: int x;

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

только время, когда вам нужно динамическое распределение, когда у вас есть данные, которые должны пережить любую заданную область.Такие данные должны выделяться динамически и в конечном итоге освобождаться, когда в них больше нет необходимости.

Основным примером использования этого является типичный связанный список .Узлы списка не могут быть локальными для какой-либо области, если вы собираетесь использовать общие функции манипуляции со списком «вставить / стереть / найти».Таким образом, каждый узел должен выделяться динамически, а функции манипулирования списком должны обеспечивать освобождение тех узлов, которые больше не являются частью списка.

Таким образом, распределение переменных принципиально и, в основном, является вопросом * 1021.* Объем .Если возможно, держите все автоматически, и вам не нужно ничего делать.При необходимости используйте динамическое распределение и позаботьтесь о том, чтобы освободить его вручную, когда это необходимо.

( Edit: Как говорит @Oli, иногда вы можете также использовать динамическое распределение в строго локальном контекстеПотому что большинство платформ ограничивают размер автоматических переменных гораздо меньшим пределом, чем размер динамической памяти. Представьте себе «огромный массив». Превышение доступного пространства для автоматических переменных обычно имеет красочное имя, такое как «переполнение кучи» или что-то подобное.)

3 голосов
/ 12 ноября 2011

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


* Исключения из этого правила включают использование таких функций, как strdup, но принцип тот же.
2 голосов
/ 12 ноября 2011

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

1 голос
/ 12 ноября 2011

Что ж, объем памяти malloc'd лежит между вызовами malloc и free или иным образом до тех пор, пока процесс не будет остановлен (то есть когда ОС очищается для процесса). Если вы никогда не позвоните free, вы получите утечку памяти. Это может произойти, когда адрес, который вы можете передать на free, выходит из области видимости до того, как вы его фактически используете - это все равно, что потерять ключи от машины, машина все еще там, но вы не можете ее вести. Ошибка, которую вы получаете, скорее всего, либо потому, что функция возвращает указатель на некоторую память, которая не была выделена с помощью malloc, либо возвращает нулевой указатель, который вы передаете free, что вы не можете сделать.

0 голосов
/ 12 ноября 2011

Если вы не хотите утечка памяти , вам нужно освободить память от malloc.

Это может быть очень сложно. Например, если // do some stuff имеет continue, свободное будет пропущено и приведет к утечке памяти. Это сложно, поэтому мы имеем shared_ptr в C ++; и, по слухам, зарплата программиста на С выше, чем на программисте на С ++.

Иногда нас не волнует утечка памяти. Если в памяти хранится что-то необходимое в течение всего времени выполнения, вы можете не освобождать ее. Пример: строка для переменной среды.

PS: Valgrind - это инструмент, помогающий обнаруживать ошибки памяти. Особенно полезно при утечке памяти.

0 голосов
/ 12 ноября 2011

malloc (n) выделяет n байтов памяти из области памяти с именем heap и затем возвращает на нее указатель типа void *.Память выделяется во время выполнения.Как только вы выделите память динамически, область действия не имеет значения, если вы держите указатель на нее при себе (или адрес ее конкретно).Например:

int* allocate_an_integer_array(int n)
{
    int* p = (int*) (malloc(sizeof(int)*n));
    return p;
}

Эта функция просто выделяет память из кучи, равной n целых чисел, и возвращает указатель на первое местоположение.Указатель можно использовать в вызывающей функции так, как вы хотите.ОБЛАСТЬ ПРИМЕНЕНИЯ не имеет значения, пока указатель находится с вами ..

free (p) возвращает память в кучу.

Единственное, что вам нужно запомнить, это освободить ее, как будтоВы не освободите его и не потеряете его адрес, это приведет к утечке памяти.Это так, потому что в соответствии с ОС вы все еще используете память, поскольку вы не освободили ее, и произойдет утечка памяти ..

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

Итак, все, что вам нужно сделать, это быть осторожным ...

Надеюсь, это поможет!

0 голосов
/ 12 ноября 2011

Вы должны освободить память, когда больше не будете к ней обращаться.Вы не должны освобождать память, если вы будете получать к ней доступ.Это доставит вам много боли.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...