2015-02-08 5 views
1

Я пытаюсь создать программу с SDL2.
В определенной части кода я пишу функции для захвата имен всех существующих файлов в указанном пути к каталогу (и сохраняю их в памяти), чтобы в другой функции я мог проверить, присутствует ли указанный файл в последний момент был проверен каталог. Я использую dirent.h, чтобы удовлетворить свои потребности, но я бегу в несколько проблем:Проблемы с захватом имен файлов с помощью SDL_strdup и аналогичных

  1. Все файлы должным образом захвачены readdir() (без исключения), однако они не всегда должным образом скопированы память после использования SDL_strdup() (код ниже).
  2. Я использую SDL_malloc()/SDL_realloc()/SDL_strdup() как можно более кросс-платформенный, чтобы избежать проблем при портировании кода (поскольку я читал, что strdup не является стандартом C).

Вот мой код:

typedef struct FileList { 
    char **files; 
    size_t num; 
} FileList; 

FileList *GetFileList(const char *path){ 
struct dirent *dp = NULL; 
DIR *dir = NULL; 
size_t i = 0; 
FileList *filelist = SDL_malloc(sizeof(FileList)); /* changing this to a calloc doesn't help */ 

/* Check if filelist == NULL */ 
filelist->files = NULL; 

dir = opendir(path); 
/* Check if dir == NULL */ 
while ((dp = readdir(dir))){ 
    if (dp->d_name[0] == '.'){ 
     continue; /* skip self, parent and all files starting with . */ 
    } 

    printf("Copying: %s\n", dp->d_name); /* Always show the name of each file */ 
    filelist->files = SDL_realloc(filelist->files, ++i); 
    filelist->files[i-1] = SDL_strdup(dp->d_name); 
    printf("Copied: %s\n\n", filelist->files[i-1]); /* Varies: either shows the file's name, either gives me plain gibberish or just nothing */ 
} 
filelist->num = i; 

closedir(dir); 

return filelist; 

}

Выход изменяется. Когда он не падает, я либо правильно копирую все имена файлов, либо получаю большинство из них, а некоторые не содержат ничего или простой тарабарщины (как прокомментировано); если он падает, иногда я получаю Segfault при использовании SDL_strdup(), в других случаях я получаю Segfault при использовании closedir().

Я даже подумал об обмене сценария SDL_realloc() с начальным распределением памяти filelist->files, указав ему количество файлов (благодаря другой функции), но я получаю ту же проблему.

Любое предложение изменить стиль кодирования на более защитный (так как я считаю, что это довольно опасно) будет оценено, хотя я пробовал все, что мог, для этого случая. В настоящее время я работаю над Mac OS X, используя встроенный gcc Apple LLVM 6.0 (clang-600.0.56).

+0

Вам не нужно вводить из 'void *' в любой тип указателя, приведение в действие не требуется. –

+0

Меня учили в колледже, поскольку они утверждали, что это старый, но оборонительный способ программирования. Я также считал, что это не нужно, поэтому я приму ваше предложение. – Keyaku

+0

[Это считается плохим стилем] (http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) –

ответ

1

Вам нужно пространство для указателей, и sizeof(char *) != 1 так

filelist->files = (char**) SDL_realloc(filelist->files, ++i); 

должен быть

filelist->files = SDL_realloc(filelist->files, ++i * sizeof(char *)); 

, но это на самом деле плохая идея, потому что SDL_realloc может вернуться NULL в этом случае вы потеряете ссылку первоначальный указатель, поэтому хорошим способом это является

void *ptr; 

ptr = SDL_realloc(filelist->files, ++i * sizeof(char *)); 
if (ptr == NULL) 
    handleThisErrorAndDoNotContinue(); 
filelist->files = ptr; 

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

+0

А, я вижу. Размер указателя важен при перераспределении.Я думал, что мне не нужно указывать, как я использовал char (1 байт), но теперь я понимаю. – Keyaku

+0

'char' всегда' 1' байт, но вы выделяете указатели, а не 'char''s. –

+0

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