Почему прикосновение к «d_name» делает вызов readdir () неудачным? - PullRequest
1 голос
/ 30 марта 2010

Я пытаюсь написать небольшой помощник для Windows, который в конечном итоге примет расширение файла в качестве аргумента и вернет количество файлов такого типа в текущем каталоге.

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

При преобразовании расширения в нижний регистр я обнаружил, что прикосновение даже к дублирующейся строке переменной d_name вызовет странное поведение, как будто больше не вызываются вызовы readdir.

Вот код, который я сейчас использую (закомментированный код является предварительным) и вывод для данного каталога:

#include <ctype.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>

char * strrch(char *string, size_t elements, char character) {
    char *reverse = string + elements;
    while (--reverse != string)
        if (*reverse == character)
            return reverse;
    return NULL;
}

void test(char *string) {
    // Even being a duplicate will make it fail:
    char *str = strdup(string);
    printf("Strings: %s %s\n", string, str);
    *str = 'a';
    printf("Strings: %s %s\n", string, str);

    //unsigned short int i = 0;
    //for (; str[i] != '\0', str++; i++)
    //   str[i] = tolower((unsigned char) str[i]);
    //puts(str);
}

int main(int argc, char **argv) {
    DIR *directory;
    struct dirent *element;   

    if (directory = opendir(".")) {
        while (element = readdir(directory))
            test(strrch(element->d_name, element->d_namlen, '.'));
        closedir(directory);
        puts(NULL);
    } else
        puts("Couldn't open the directory.\n");
}

Вывод без изменения дубликата (изменение и второй комментарий printf прокомментированы):

Strings: (null) (null)
Strings: . .
Strings: .exe .exe
Strings: .pdf .pdf
Strings: .c .c
Strings: .ini .ini
Strings: .pdf .pdf
Strings: .pdf .pdf
Strings: .pdf .pdf
Strings: .flac .flac
Strings: .FLAC .FLAC
Strings: .lnk .lnk
Strings: .URL .URL

Вывод того же каталога (с кодом выше, с 2 printf s):

Strings: (null) (null)

Что-то не так? Это проблема компилятора? Я использую GCC 4.4.3 в Windows (MinGW) прямо сейчас.

Большое спасибо за вашу помощь.

Кстати, есть ли другой способ работы с файлами и каталогами в среде Windows, не использующий функции POSIX?

1 Ответ

2 голосов
/ 30 марта 2010

В системах Windows «родным» API является не POSIX, а Win32. В Win32 попробуйте FindFirstFile () и FindNextFile () .

Что касается вашего кода: ваша первая строка показывает, что первый вызов test() с указателем NULL (это то, что ваша функция strrch() возвращает для имени файла "."). strdup() достаточно любезен, чтобы не зависнуть на NULL, но возвращает NULL. Затем вы модифицируете «строку», которой не существует. Это разыменование нулевого указателя, после чего все происходит. В системе Unix это будет означать немедленное завершение работы приложения с сегфоутом. В Windows это, вероятно, зависит от марки ОС.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...