2017-02-15 13 views
0

Я создал программу, которая открывает файл (читает двоичный файл) и сохраняет все слова (в файле) в массиве символов (динамически распределяется по основанию длины слова) ,
Это код:Освобождение памяти в массивах

char **leggi_stringhe(const char *filename, size_t *size) { 
    FILE *f = fopen(filename, "rb"); 
    if (f == NULL) { 
     *size = 0; 
     return NULL; 
    } 

    int x; 

    if (fread(&x, 1, 4, f) != 4) { 
     *size = 0; 
     return NULL; 
    } 

    char **stringhe = malloc((x) * sizeof(char)); 

    for (int i = 0; i < x; i++) { 
     int z = 0; 
     if (fread(&z, 1, 4, f) != 4) { 
      *size = 0; 
      return NULL; 
     } 

     stringhe[i] = malloc((z)* sizeof(char)); 
     if (fread(stringhe[i], 1, z, f) != z) { 
      *size = 0; 
      return NULL; 
     } 
     stringhe[i][z] = 0; 
    } 
    *size = x; 
    fclose(f); 
    return stringhe; 
} 

int main(void) { 
    size_t t; 
    char **a = leggi_stringhe("file1.bin", &t); 

    for (int i = 0; i < t; i++) 
     free(a[i]); 
    free(a);; 
} 

Программа работает, но у меня есть проблемы с освобождением памяти. После вызова из leggi_stringhe функции, переменная содержит:

a[0] = "first" 
a[1] = "second" 
a[2] = "third" 

, но когда я пытаюсь освободить весь в переменного, как я писал, отладчик останавливается с предупреждением.
Я был вдохновлен этим вопросом для написания своего кода Using Dynamic Memory allocation for arrays, но не понимаю, почему я получаю эту ошибку, когда пытаюсь освободить.

+1

Обратите внимание, что 'sizeof (char)' равно 1. –

+3

просто увидел, что: 'sizeof (char *)' должно быть –

+1

'fread (& z, 1, 4, f)'? Почему вы предполагаете, что 'z' составляет четыре байта? Вы также неявно предполагаете, что ваш файл данных поступает с машины с той же конечностью, что и с той, на которую вы обрабатываете. –

ответ

4

Ваш первоначальный вызов malloc неверен. Вы назначаете место для xсимволов, не для указателей на char.

Ваш второй вызов внутри цикла неверен, поскольку вы не выделяете место для терминатора.

И, наконец, и не связаны с проблемами, о которых вы спрашиваете, но если вызовы, вызываемые внутри цикла, не пройдут, у вас будут утечки памяти.

+3

К OP: @ M41Npain и, пожалуйста, проверьте, что 'malloc()' не возвратил 'NULL'. Это может быть слишком много для этого кода, но это привычка, что вы ДОЛЖНЫ развить –

+0

@IharobAlAsimi cplusplus.com say * Если функции не удалось выделить запрошенный блок памяти, возвращается нулевой указатель. * Что это значит? – Amarildo

+1

@ M41Npain В C 'NULL' является стандартным символом для нулевого указателя. Если в вашем случае 'stringhe' равно' NULL' после первого вызова 'malloc', то распределение не удалось, и вы не должны продолжать использовать указатель. –

1

Есть некоторые проблемы с вашим кодом:

  • Эта линия:

    char **stringhe = malloc((x) * sizeof(char)); 
    

    должно быть:

    char **stringhe = malloc((x) * sizeof(char*)); /* or sizeof *stringhe */ 
    

    Как вам нужно выделить xchar* указатели для stringhe ,

  • В вашем первом цикле for вы не добавляете +1 для нуль-терминатора. Он должен быть вместо этого:

    stringhe[i] = malloc(z+1); /* sizeof(char) = 1 */ 
    
  • Вы должны проверить возвращение malloc(). Он может вернуть NULL, если он не увенчался успехом. Вы можете сделать это, просто проверив if (ptr == NULL), затем выйдите из программы. Было бы небезопасно разрешить провал malloc() для продолжения в программе.

  • for (int i = 0; i < t; i++) сравнивает int с size_t. Это должно быть for (size_t i = 0; i < t; i++).

+0

Я не добавлял +1 в 'stringhe [i] = malloc ((z) * sizeof (char));' потому что после того, как malloc я вижу с отладчиком, функция malloc всегда выделяет больше пространства, которое необходимо, на самом деле после этого я добавил 'stringhe [i] [z] = 0;', чтобы вырезать остальные – Amarildo

+1

@ M41Npain При назначении указателей 'char *' всегда можно добавить дополнительный +1 при использовании 'malloc()'. Он может работать сейчас, но в будущем, если вы этого не сделаете, и 'malloc()' не выделяет достаточно места для '\ 0', тогда вы будете получать доступ за пределы того, что было выделено. – RoadRunner

+0

gotcha, спасибо. – Amarildo