malloc и scope

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

... free (): недопустимый следующий размер (быстрый): ...

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

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 находится в функции, и я возвращаю var, который использовал malloc ()? Как насчет цикла for или while? Имеет ли malloc-ing для массива struct те же правила, что и для указателя строки/символа?

Я собираюсь из ошибок, которые я получаю в gcc по сбою программы, что я просто не понимаю malloc и бесплатно. Я провел свое качественное время с Google, и я все еще сталкиваюсь с кирпичными стенами. Есть ли хорошие ресурсы, которые вы нашли? Все, что я вижу, говорит, что всякий раз, когда я использую malloc, мне нужно использовать бесплатно. Но потом я пробую это, и моя программа выйдет из строя. Так может быть, это отличается от сферы переменной? Сохраняет ли 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?
}

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

Надеюсь, у меня есть смысл ...

1
все, что вы malloc (), вы освобождаете (один раз), когда вам больше не нужно его использовать.
добавлено автор Mitch Wheat, источник
вы malloc'ing нулевые байты ...? bytes.com/topic/c/answers/578467- what-malloc-0-should-return & zwnj; s EDIT: Просто понял, что это не имеет значения, поскольку вы все еще можете бесплатно (... ) указатель, независимо.
добавлено автор cwharris, источник

7 ответы

malloc() is C's dynamic allocator. You have to understand the difference between automatic (scoped) and dynamic (manual) variables.

Automatic variables live for the duration of their scope. They're the ones you declare without any decoration: int x;

Most variables in a C program should be automatic, since they are local to some piece of code (e.g. a function, or a loop), and they communicate via function calls and return values.

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

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

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

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

5
добавлено
+1 для рекомендации избегать динамического распределения, когда это возможно.
добавлено автор R.., источник
@OliCharlesworth: ах, да, еще один хороший момент! Ред.
добавлено автор Kerrek SB, источник
Удивительное объяснение того, когда это (не) подходит для malloc ate
добавлено автор g33kz0r, источник
То, как вы это объяснили, определенно помогло. Исходя из PHP, где $ x = "некоторая строка"; , я пытался использовать malloc имеет замену для назначения; более разумно описать его как динамическое, а не автоматическое, распределение
добавлено автор cegfault, источник
Экземпляр динамического распределения, который не доходит до области ожидания, - это когда вам нужен массивный массив (например, миллион элементов), который разбивает стек.
добавлено автор Oliver Charlesworth, источник

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


* Исключения из этого правила включают использование таких функций, как strdup , но принцип тот же.
3
добавлено
@xixonia: авария - лучший сценарий, а не то, что вы должны ожидать. В худшем случае вы получаете корень злоумышленника.
добавлено автор R.., источник
@xixonia: Готово!
добавлено автор Oliver Charlesworth, источник
@R .., все это заставляет меня хотеть вернуться к C :)
добавлено автор cwharris, источник
Здесь важно отметить, что вызов free (...) дважды может привести к сбою.
добавлено автор cwharris, источник

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

2
добавлено

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

1
добавлено
Строго говоря, слово в C - это «продолжительность хранения», а не «время жизни». :-)
добавлено автор R.., источник
@OliverCharlesworth, oh snap боевые слова :: pops popcorn ::
добавлено автор user1717828, источник
Вы имеете в виду «жизнь», а не «область». Область применяется к идентификаторам, а не к объектам.
добавлено автор Oliver Charlesworth, источник
@R ..: Нет, я действительно имею в виду «жизнь»; см. пункт 6.2.4.
добавлено автор Oliver Charlesworth, источник

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

0
добавлено

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

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

Эта функция просто выделяет память из кучи, равную n целых чисел, и возвращает указатель на первое место. Указатель может использоваться в вызывающей функции так, как вы хотите. SCOPE не имеет значения, если указатель с вами.

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

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

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

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

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

0
добавлено

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

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

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

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

0
добавлено
Если мои коллеги оставляют утечку памяти в библиотечном коде, я поднимаю билет и заставляю его исправлять его ...
добавлено автор Oliver Charlesworth, источник
Нет, мы этого не делаем, мы можем просто правильно очистить нашу память.
добавлено автор Oliver Charlesworth, источник
Пренебрегая чем-то свободным только потому, что это пожизненная жизнь, все исполнение - очень плохая практика. Для начала он выгружает выходные данные Valgrind с ошибками.
добавлено автор Oliver Charlesworth, источник
Согласен. Но мы должны жить с этим.
добавлено автор Cha Cha, источник
Вы не только, если являетесь единственным, кто пишет коды, и не используйте какую-либо библиотеку. Реальность - это код ваших коллег; и библиотеки, на которые вы полагаетесь, могут не освобождать память.
добавлено автор Cha Cha, источник
Хорошо, у вас есть точка. Я собираюсь убедить своих коллег освободить память для putenv (strdup (...)). Я постараюсь заставить их работать. Спасибо.
добавлено автор Cha Cha, источник