Создание программы, которая перечисляет файлы в каталоге и сортирует выходные данные

#c #sorting #malloc #ls

Вопрос:

Я использую opendir(.) , чтобы открыть путь к каталогу, из которого я хочу читать. Затем я использую readdir цикл для просмотра всех файлов и каталогов в текущем каталоге. Затем у меня char** есть список для хранения содержимого readdir. Затем я делаю сортировку **list , чтобы привести ее в лексиграфический порядок. Я продолжаю получать ошибку переполнения при сортировке выходных данных только тогда, когда у меня есть файл длиной более 63 символов. Почему это так и как я могу это исправить?

 void ls_short() {
    char **list = NULL;
    int count = 0;
    DIR  *dir;
    struct dirent *rd;
    dir = opendir(".");
    // check to make sure that we can open the directory
    if(dir == NULL){
        perror("Not able to open The current directory.");
        exit(EXIT_FAILURE);
    }
    
    while((rd = readdir(dir)) != NULL){
        list = realloc(list, (count 1)*sizeof(*list));
        list[count] = rd ->d_name;
          count;
        printf("%sn",rd ->d_name);
    }
    printf("here we will print the listn");
    for (int i = 0; i < count;i  ){
        printf("%sn",list[i]);
    }
    printf("Now we print the list in order and also get rid of . and .. directoryn");
    list = realloc(list, (count 1)*sizeof(*list));
    list[count] = "";
    for (int i = 0; i < count - 1; i  ){
        for (int j = 0; j < count - i - 1; j  ){
            if (strcasecmp(list[j], list[j   1]) > 0) {
                    char* temp;
                    temp = (char*)calloc(count, sizeof(char)*256);
                    strcpy(temp, list[j]);
                    strcpy(list[j], list[j   1]);
                    strcpy(list[j   1], temp);
                    free(temp);
            }
        }
    }
    for (int i = 2; i < count;i  ){
        printf("%sn",list[i]);
    }
    closedir(dir);
}
 

Это ошибка, которую я получаю:

скриншот сообщений об ошибках

 =================================================================
==43335==ERROR: AddressSanitizer: strcpy-param-overlap: memory ranges [0x6250000001fd,0x625000000220) and [0x62500000021d, 0x625000000240) overlap
    #0 0x103ef03ef in wrap_strcpy 0xaf (libclang_rt.asan_osx_dynamic.dylib:x86_64h 0x433ef)
    #1 0x103e9aa5d in ls_short ls.c:61
    #2 0x103e9a5c4 in main ls.c:16
    #3 0x7fff20379620 in start 0x0 (libdyld.dylib:x86_64 0x15620)

0x6250000001fd is located 253 bytes inside of 8192-byte region [0x625000000100,0x625000002100)
allocated by thread T0 here:
    #0 0x103ef54c0 in wrap_malloc 0xa0 (libclang_rt.asan_osx_dynamic.dylib:x86_64h 0x484c0)
    #1 0x7fff2025b0fe in _readdir_unlocked$INODE64 0x6d (libsystem_c.dylib:x86_64 0x2a0fe)
    #2 0x7fff2025b227 in readdir$INODE64 0x22 (libsystem_c.dylib:x86_64 0x2a227)
    #3 0x103e9a6ad in ls_short ls.c:42
    #4 0x103e9a5c4 in main ls.c:16
    #5 0x7fff20379620 in start 0x0 (libdyld.dylib:x86_64 0x15620)

0x62500000021d is located 285 bytes inside of 8192-byte region [0x625000000100,0x625000002100)
allocated by thread T0 here:
    #0 0x103ef54c0 in wrap_malloc 0xa0 (libclang_rt.asan_osx_dynamic.dylib:x86_64h 0x484c0)
    #1 0x7fff2025b0fe in _readdir_unlocked$INODE64 0x6d (libsystem_c.dylib:x86_64 0x2a0fe)
    #2 0x7fff2025b227 in readdir$INODE64 0x22 (libsystem_c.dylib:x86_64 0x2a227)
    #3 0x103e9a6ad in ls_short ls.c:42
    #4 0x103e9a5c4 in main ls.c:16
    #5 0x7fff20379620 in start 0x0 (libdyld.dylib:x86_64 0x15620)

SUMMARY: AddressSanitizer: strcpy-param-overlap (libclang_rt.asan_osx_dynamic.dylib:x86_64h 0x433ef) in wrap_strcpy 0xaf
==43335==ABORTING
Abort trap: 6
 

Комментарии:

1. Пожалуйста, опубликуйте ошибку в виде обычного текста, а не скриншота.

2. Есть ли причина, по которой вы вручную катите сортировку пузырьков, а не просто используете qsort ?

3. @Barmar Я опубликовал ошибку в текстовом формате

Ответ №1:

readdir() имеет статический буфер для rd->d_name , который он повторно использует каждый раз, когда вы его вызываете, поэтому все ваши list элементы указывают на одну и ту же строку.

Вы должны сделать копию строк, когда назначаете их массиву.

 list[count] = strdup(rd->d_name);
 

И когда вы сортируете, не копируйте имена между строками, просто меняйте местами указатели.

             if (strcasecmp(list[j], list[j   1]) > 0) {
                char* temp;
                temp = list[j];
                list[j] = list[j 1];
                list[j 1] = temp;
            }
 

Комментарии:

1. Это не сработает. Он выделяет достаточно памяти только для этого имени файла. Но его дизайн требует, чтобы каждый строковый буфер был достаточно большим, чтобы содержать самое большое имя файла. (Посмотрите на такой код strcpy(list[j], list[j 1]); .)

2. Хороший улов. Я добавил, как это сделать, поменяв местами указатели вместо копирования строк.

Ответ №2:

     while((rd = readdir(dir)) != NULL){
        list = realloc(list, (count 1)*sizeof(*list));
        list[count] = rd ->d_name;
          count;
        printf("%sn",rd ->d_name);
    }
 

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

Вам нужно перейти list[count] = rd ->d_name; на что-то вроде:

     list[count] = malloc(256);
    strcpy(list[count], rd->d_name);
 

Кроме того, вам не нужно выделять новую память для строк при сортировке. Если у вас уже выделена память для каждой строки, которую вам нужно сохранить (что необходимо, или ваш список уже разбит), почему для изменения порядка требуется выделение новой памяти для хранения строк?

Комментарии:

1. Эти две строки кода исправили проблему. Мне просто любопытно, почему программа, казалось, работала нормально, пока длина имени файла не стала больше 63, а также почему я должен использовать strcpy ? также в отношении выделения новой памяти для сортировки вы имеете в виду временную или список? Спасибо вам за вашу помощь.