Неверное чтение — Valgrind и C

Новичок в C и Valgrind и ручном управлении памятью, и у меня возникли проблемы с поиском ошибки, которую я получаю при запуске Valgrind. У меня есть эта функция, которая получает строки от пользователя:

char **get_fragments_from_user(){
    // No more than 20k strings containing at most 1k characters
    char **strings = malloc(20000 * sizeof(char *));

    char tempstring[MAX_INPUT]; //MAX_INPUT = 1001
    int count = 0;
    while(true){
        printf("\n> ");
        fgets(tempstring, MAX_INPUT, stdin);
        if((strlen(tempstring) > 0) && (tempstring[strlen(tempstring) - 1] == '\n')){
            tempstring[strlen(tempstring) - 1] = '\0';
        }
        if(tempstring[0] == 'q') break;
        strings[count] = malloc(sizeof(char) * (strlen(tempstring)+1));
        strcpy(strings[count], tempstring);
        count++;
    }
    int i = 0;
    char **fstrings = malloc((count)*sizeof(char *)); // count+1 needed? Something I tried removing while debugging
    for(i = 0; i < count; i++){
        fstrings[i] = malloc(sizeof(char) * (strlen(strings[i])+1));
        strcpy(fstrings[i], strings[i]);
        free(strings[i]);
    }
    free(strings);
    return fstrings;
}

Идея здесь состоит в том, чтобы просто получить строки и поместить их в массив. Сначала я выделяю массив, который достаточно велик, чтобы вместить максимальное количество строк, которые можно когда-либо ввести (20 000), но затем я изменяю размер массива, чтобы не выделять больше памяти, чем требуется для каждой строки. Я немного смущен приведенным выше кодом, так как он менее чистый, чем все, что я написал бы на другом языке, но это был мой первый проход.

Затем я получаю «Недопустимое чтение размера 8» от Valgrind, когда пытаюсь вычислить количество строк в массиве с помощью этой функции:

int lengthOf(char **arr){
    int i = 0;
    while(arr[i] != NULL){
        i++;
    }
    return i;
}

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


person Alex Alifimoff    schedule 29.08.2014    source источник
comment
предложение, char **fstrings = calloc(count+1, sizeof(char *));   -  person BLUEPIXY    schedule 29.08.2014
comment
Плюс: до return fstrings; --›› fstrings[i] = NULL;   -  person wildplasser    schedule 29.08.2014
comment
Итак, если я пересчитаю +1 и преобразую malloc в calloc, это избавит меня от первоначальной проблемы, которая у меня была, но теперь у меня есть некоторые другие проблемы, но я сначала посмотрю, смогу ли я их решить. Еще одно недопустимое чтение размера 1.   -  person Alex Alifimoff    schedule 29.08.2014
comment
@wildplasser: Зачем это делать? Моя интуиция подсказывает, что это гарантирует, что функция lengthOf будет работать правильно, но я не совсем уверен, что это правильно.   -  person Alex Alifimoff    schedule 29.08.2014
comment
Функция lengthof() считает до тех пор, пока не увидит NULL в массиве. Вы не поместили туда NULL, так почему он должен быть?   -  person wildplasser    schedule 29.08.2014
comment
Использование calloc фактически исправляет эту ошибку, поскольку память инициализируется 0   -  person Rob11311    schedule 01.02.2016


Ответы (1)


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

Вместо того, чтобы делать:

malloc(count * sizeof(char *));

Я должен был выделить count+1, так что либо:

malloc((count + 1) * sizeof(char *))

or

calloc((count + 1), sizeof(char *));
person Alex Alifimoff    schedule 29.08.2014
comment
Нет очевидной необходимости копировать каждую строку дважды, вы можете просто назначить указатели с помощью fstrings[i] = strings[i], избегая malloc, strcpy и free в цикле копирования. Строки/fstrings должны заканчиваться записью NULL, поэтому либо используйте calloc, либо malloc с присвоением strings[count] = 0 & fstrings[count]. - person Rob11311; 01.02.2016