Попытка изучить правильную обработку памяти в C malloc, realloc и free

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

*** glibc detected *** ./a.out: realloc(): invalid next size:

Насколько я могу судить, ничего не меняется. Почему realloc будет работать с массивом из 8, но не с массивом из 16?

И второй вопрос касается утечек памяти. Я все еще не уверен, что мне нужно освободить в программе. Другие посоветовали мне освободить inputcpy. Это все здесь? Кроме того, на каком этапе программы я хочу его освободить?

#define DEBUG 1

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

char ** getArgs( char *input,  char **args, int ct);
char ** args;

int main(int argc, char* argv[]) {
  char input[]="echo arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 arg10 arg11 arg12 arg13";
  char inputcpy[strlen(input)];
  strcpy(inputcpy, input);
  char * prog=strtok(input, " ");

  /*Saving space for an array of 8 strings*/
  args=( char **) calloc(8, sizeof( char *));  

  getArgs(inputcpy, args, 1);

  if(DEBUG) {
    printf("arg address after: %p\n", args);
  }

  int q;
  int pid=fork();
  if (pid==0) {
    execvp(prog, args); 
    return 0;
  }
  else {
    int status=0;
    wait(&status);
  }
}

char ** getArgs( char *input,  char **args, int ct) {
  int adj=(ct-1)*8;//if we recurse, this ensures correct indexes are used
  char *inputcpy=malloc(strlen(input));
  strcpy(inputcpy, input);

  /*Initialize indexes/Prepare for copying*/
  int i; 
  if(ct==1) {
    i=1;
    args[0]=" "; //quick hack to ensure all args are used by exec()
  }
  else
    i=0;

  /**Actually do the copying now**/
  char *temp=strtok(NULL, " ");
  args[adj+i++]=temp;
  while (temp != NULL && i<8) {
    temp=strtok(NULL, " ");
    args[adj+i++]=temp;
  }   

  /*If there are more args than we have room for*/
  if(i>=8){
    /*Increase the array to store 8 more strings*/
    args= (char **) realloc(args, sizeof(args)+8*sizeof(char *) );
    getArgs(inputcpy, args, (++ct) );
  }   

  return NULL;
}

person user1209326    schedule 26.02.2012    source источник
comment
Это очень большой объем кода, поэтому я опущу его и резюмирую. Если вы new что-то, delete это. Если вы что-то malloc, free это. sizeof дает вам размер args (указатель), а не то, на что он указывает, что выглядит вашей ошибкой.   -  person Kieren Johnstone    schedule 26.02.2012
comment
char *inputcpy=malloc(strlen(input)); должно быть char *inputcpy=malloc(strlen(input) + 1);, так как вы должны учитывать нулевой символ.   -  person Ed Heal    schedule 26.02.2012


Ответы (2)


 char *inputcpy=malloc(strlen(input));
 strcpy(inputcpy, input);

вы не выделяете достаточно места для своей строки, должно быть: malloc(strlen(input) + 1);

То же самое:

 char inputcpy[strlen(input)];
 strcpy(inputcpy, input);

Строка - это последовательность символов с завершением, включающая нулевой символ, а длина строки - это количество символов, предшествующих нулевым символам.

Также вы неправильно используете realloc:

args= (char **) realloc(args, sizeof(args)+8*sizeof(char *) );

При таком использовании есть потенциальная утечка памяти.

Что касается free, то, что вы должны сделать, очень просто: каждому malloc должен соответствовать free.

person ouah    schedule 26.02.2012
comment
Спасибо за ответ и указание на нехватку места для нулевого символа - исправлено! Однако у меня есть вопрос по поводу вашего realloc комментария. Если realloc уже переназначает аргументы, как я могу освободить предыдущие аргументы? Использование var=realloc(var, size) - плохая практика? - person user1209326; 26.02.2012
comment
@ user1209326 да, потому что если realloc вернет NULL, он перезапишет args, и у вас не будет возможности free исходный args. В вашем коде вы не проверяете возвращаемые значения библиотечных функций, которые подвергают вашу программу случайным проблемам. - person ouah; 26.02.2012

Я отвечу на ваш последний вопрос: а также на каком этапе программы я хочу его освободить?

Что ж, рекомендуется освободить его прямо перед возвращением функции, которая вызвала malloc. Если вы это сделаете, вам не придется беспокоиться об утечке памяти.

Однако вызывающая функция, в вашем случае main, также может вызывать free (), когда ваша функция getArgs () завершена и возвращает управление main. Это потому, что можно использовать другую переменную-указатель с free (); вам просто нужно убедиться, что новый указатель хранит тот же адрес.

person leocod    schedule 27.02.2012