Грешка при сегментиране при разпределяне на паметта

Имам две функции open_files и read_bytes. Когато извикам само open_files, всичко работи както трябва, но ако извикам read_bytes след това, получавам грешка в сегментирането в open_files. Използвам gcc като компилатор.

open_files е функция, която търси в директория и попълва структура, съдържаща името на файла и дължината на масива от символи.

read_bytes е функция без код и връща само 1.

Структурата за имена на файлове

struct file_name{
    char * name;
    int length;
};

Основната функция:

int main(int argc, char **argv){
    struct file_name ** files;
    int file_length;
    unsigned char * hex;
    long int bytesLength;
    printf("CRAP");
    getchar();
    //Function open_files works if read_bytes function is not called....
    if(open_files(files, &file_length) >= 0){
        printf("CRAP2");
        getchar();
        if (read_bytes(hex, &bytesLength, files[0]->name) >= 0){
            for(int i = 0; i < bytesLength; ++i){
                printf("%X\n",hex[i]);
            }
        }
    }
    else{
        printf("Something went wrong");
    }

    printf("%s\n", "Helluuuuuu");

    free_memory(files, file_length);

    return 0;
}

Функцията open_files създава структура file_name за всеки файл в директория.

int open_files(struct file_name ** files, unsigned int * length){
    DIR * dir;
    struct dirent * ent;
    int count = 0;
    if((dir = opendir("TestFiles")) != NULL){

        while((ent = readdir(dir)) != NULL ){
            ++count;

        }
        count -= 2;
        closedir(dir);
    }
    else{
        //Couldn't open directory
        perror("");
        return -1;
    }
    printf("working");
    getchar();
    //Allocate memory
    *files = malloc(count * sizeof(struct file_name *));
    printf("not working");
    getchar();
    *length = count;

    if((dir = opendir("TestFiles")) != NULL){
        count = 0;
        while((ent = readdir(dir)) != NULL ){
            if(strcmp(ent->d_name,".") != 0 && strcmp(ent->d_name,"..") != 0){
                struct file_name * file = malloc(sizeof(struct file_name));
                file->name = malloc(strlen(ent->d_name));
                strcpy(file->name,ent->d_name);
                file->length = strlen(ent->d_name);
                files[count] = file;
                ++count;
            }
        }
        closedir(dir);
    }
    else{
        //Couldn't open directory
        perror("");
        return -1;
    }

    return 0;
}

read_bytes е празна функция, която връща 1:

int read_bytes(unsigned char * hex, long int * length, char * file){
    //FILE * fp;
    //*length = file_size(file);
    //printf("%li\n",*length );

    //fp = fopen("TestFiles/first.jpg", "r");
    //fread(hex, 1, *length, fp);
    //fclose(fp);

    return 1;
}

person Olof    schedule 31.05.2016    source източник
comment
file->name = malloc(strlen(ent->d_name)); --› file->name = malloc(strlen(ent->d_name)+1); (+1) Може би и други проблеми.   -  person chux - Reinstate Monica    schedule 31.05.2016
comment
bytesLength съдържа боклук, доколкото мисля. не съхранявате никаква стойност и не я предавате на for цикъл.   -  person Mazhar    schedule 31.05.2016
comment
@chux Добавих +1 и все още грешка в сегментирането   -  person Olof    schedule 31.05.2016
comment
@Mazhar Планирано е bytesLength да получи стойността си от функцията read_bytes.   -  person Olof    schedule 31.05.2016
comment
Създаването на MCVE ще направи много по-лесно определянето на причината не само за вас, но и за тези, които се опитват да ви помогнат. Освен това проблеми като този обикновено могат лесно да бъдат разрешени с помощта на програма за отстраняване на грешки. Опитахте ли го вече? И накрая, обърнете внимание на всички предупреждения на компилатора, които се случват, когато компилирате вашата програма - опитвайки се да компилирате това, GCC дава много предупреждения и дори грешка. Ако не получавате предупреждения или грешки при компилиране, трябва да преминете към компилатор, който ги показва.   -  person Random Davis    schedule 31.05.2016
comment
Предавате на open_files() неинициализиран указател към указател от main() (files), след което се опитвате да зададете към какво сочи, за да сочи към новоразпределен блок памет. Това може да причини нарушение на достъпа и ако не беше, показалецът все още нямаше да е наличен в main(). (подсказка: предайте адреса на указател от main(), вместо стойността на (неинициализиран) указател към указател)   -  person Dmitri    schedule 31.05.2016
comment
Има и редица други проблеми... например извиквате read_bytes() за първия запис, без да проверявате броя на върнатите записи open_files() (какво се случва с празна директория, където open_files() успява, но с 0 имена на файлове?)... и не се справяте със случая, когато се създават нови файлове в директорията между вашия opendir() за получаване на броя и opendir() за четене на имената на файловете...   -  person Dmitri    schedule 31.05.2016


Отговори (1)


Ти имаш

*files = malloc(count * sizeof(struct file_name *));

за да разпределите вашия масив от указатели, което не е правилно. Масив от структурни указатели ще има тип struct file_name **, но вие го присвоявате на struct file_name *·

След това правите:

files[count] = file;

За count == 0, който презаписва адреса, върнат от malloc() (files[0] == *files), за count > 0 той извиква Недефинирано поведение.

Можете или да подадете struct file_name *** до open_files() и да промените

files[count] = file; 

to

(*files)[count] = file;

или разпределете масив от структури:

 *files = malloc(count * sizeof(struct file_name) );  
 ....
        if(strcmp(ent->d_name,".") != 0 && strcmp(ent->d_name,"..") != 0){
            struct file_name * file = (*files) + count;  // struct is already allocated (alternatively: &((*files)[count])
            file->name = malloc(strlen(ent->d_name)+1);
            strcpy(file->name,ent->d_name);
            file->length = strlen(ent->d_name);
            ++count;
        }

В main() трябва да подадете &files до open_files() и в двата случая. Ако изберете второто решение, моля, променете

struct file_name ** files;

to

struct file_name * files;

и

files[0]->nam 

to

files[0].name

Моля, обърнете внимание на file->name = malloc(strlen(ent->d_name)+1);, което е необходимо и в двата случая, както вече беше споменато

person Ingo Leonhardt    schedule 31.05.2016
comment
@alk прав си, разбира се, погледнах само самата функция. Добавих го, благодаря - person Ingo Leonhardt; 31.05.2016
comment
@IngoLeonhardt На линия struct file_name * file = &files[count]; // struct is already allocated получавам: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types] struct file_name * file = &files[count]; // struct is already - person Olof; 31.05.2016