Копирование и освобождение указателя malloc’ed

#c #pointers #c99

#c #указатели #c99

Вопрос:

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

 Current implementation (with memory leak):

// This code has been greatly simplified
// and as such does not appear to have any purpose
int foo(){
  int bestval = 0;
  char *best;
  char *match;
  for (int i=0;i<3;i  ) {
      int returnValue = bar(amp;best);
      if (returnValue > 10) {
        (1)
         match = best;
      }
  }

  printf("%s", match); 
  (2)    
  return 0;
}


int bar(char ** best) {
  char*s = "Hello!";
  *best = malloc(strlen(s)   1);
  strcpy(*best,s);
  return 0;
}
  

Два вопроса

  1. Если бы мне пришлось освобождать память в (1), а не в (2), как бы я это сделал, чтобы в match все еще было то, что содержалось в best?

  2. Должен ли я выполнять strcpy, чтобы копировать наилучшим образом, чтобы соответствовать? Если да, должен ли я выполнить другой malloc в foo?

Комментарии:

1. Предполагая, что в точке два есть свободное значение, опубликованный вами код не протекает, однако после ‘2’ совпадение также недопустимо после этой точки… Вы запускаете этот код в цикле?

2. Зачем вам нужны 2 указателя best и match ? Вы можете просто использовать best и free это в (2).

3. @forsvarir, да, я запускаю его в цикле, именно поэтому я рассматриваю возможность реализации free в (1).

4. Является ли цикл внутри Foo или внешним по отношению к нему? Если это есть в нем, это, вероятно, имеет отношение к вашей утечке памяти … можете ли вы указать, где начинается / заканчивается цикл в вашем фрагменте кода

5. Цикл вокруг bar() — я подозреваю, что вы можете быть правы — мое общее ощущение таково, что в каждом из циклов я выполняю malloc и у меня нет подходящей возможности освободить его. Мы были бы весьма признательны за некоторое направление.

Ответ №1:

Небольшая попытка в темноте, предполагая, что в Foo есть цикл…

 int foo()
{   
    int bestval = 0;   
    char *best;   
    char *match = 0;    // initialize to null

    // start some loop
    for (int i=0;i<3;i  ) {       

        // fetch the next best value...
        int returnValue = bar(amp;best);       
        // some check (if best is really best!)
        if (returnValue > 10) {
            // if match has previously been populated, free it
            if(match) {
                free(match);
            }
            // save the new best value
            match = best;   
        }
        else {
           // not saving best in match, so free it!
           free(best);
        }
    }
    // end some loop

    // only do this if match was successful?!?
    if(match) {
        printf("%s", match);    
        // clean up once the best of the best has been used...
        free(match);
    }
    return 0; 
} 
  

Комментарии:

1. Мне это нравится, и в этом есть смысл. Я попробую это и сообщу вам о своих результатах!

2. @Rio: Я только что добавил еще один свободный… если вы не сохраняете best в match, вам нужно убедиться, что вы его освободили…

3. Последнее было решающим!

4. Как освободить автоматическую переменную в стеке (например, match and best )?!!

Ответ №2:

На панели функций strcpy должен выглядеть как

 strcpy(*best,s);
  

В основной функции вы можете скопировать значение, на которое лучше всего указывает, с помощью

 strcpy(match, best);
free(best);
  

совпадение должно указывать на допустимый блок памяти раньше. Если вы выполните

 match = best;
free(best);
  

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

Комментарии:

1. Извините, все еще немного на C 😉 Исправлено.

Ответ №3:

Вам нужно знать размер строки.
В (1) Вы бы назначили адрес адреса памяти, который уже был освобожден, вам нужно выполнить другой malloc для match*=malloc(sizestr) , а затем скопировать его с помощью memmove или strcpy, если вы хотите освободить наилучшим образом.

Если я правильно понял, вы хотите скопировать строку в best, затем освободить память bests и назначить ptr для соответствия? если вы освобождаете большую часть памяти перед перемещением в другое место, вы теряете ее содержимое, и если вы хотите скопировать ее в другое место, сначала вам нужно выделить память, куда вы хотите ее скопировать, поэтому для этого кода вам нужно 2 mallocs.

Ответ №4:

Если бы мне пришлось освобождать память в (1), а не в (2), как бы я это сделал, чтобы в match все еще было то, что содержалось в best?

Если вы free в position (1) , невозможно сделать это так, чтобы match все еще было то, что содержалось в best .

Должен ли я выполнять strcpy, чтобы копировать наилучшим образом, чтобы соответствовать? Если да, должен ли я выполнить другой malloc в foo?

   match = best;
  

С помощью приведенного выше оператора оба указывают на одно и то же местоположение. Таким образом, в strcpy этом вообще нет необходимости. Для этого выделите память для match указания, длина которого best 1 равна, а затем выполните strcpy .

Ответ №5:

Копирование значения указателя не копирует базовую память. Так что либо не делайте этого, free(best) пока не закончите с match , либо вам понадобится malloc новый буфер и, например, memcpy() содержимое из одного буфера в другой.

Ответ №6:

Да, вы можете malloc и strcpy :

 match = malloc(strlen(best)   1);
strcpy(match, best);
  

Но, если ваша реализация предусматривает это, вы можете использовать strdup() функцию, которая намного проще:

 match = strdup(best);
  

Если у вас еще нет strdup(), хорошей идеей будет создать его самостоятельно.

Ответ №7:

Ваше текущее назначение просто присваивает указатели одному и тому же буферу. Если вы затем free() удалите этот буфер, вы удалите то, что здесь содержится (и, следовательно, разыменовывать его — плохая идея).
Вам не нужно использовать strcpy() для копирования наилучшего соответствия — вам будет лучше освободить его после printf() (или последней точки, в которой это необходимо). Нет смысла чрезмерно усложнять ситуацию дополнительным вызовом функции или шестью, просто помните о free() памяти, которую вы выделили в конце каждой функции!