Невалидно четене - 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