2017-03-27 11 views
1

ディレクトリ内のすべてのフォルダとファイルをファイルサイズと共に再帰的にリストするプログラムを作成しようとしています。私はプログラムが深いサブフォルダの1つのレベルに行くように見えるので、私はまだ最初の部分に取り組んでいます。サブフォルダを再帰的に訪問することはできません

誰でも問題を見つけることができますか?私は立ち往生している。

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <string.h> 
#include <strings.h> 
#include <dirent.h> 
#include <unistd.h> 

void listdir(const char *name) { 
    DIR *dir; 
    struct dirent *entry; 
    int file_size; 

    if (!(dir = opendir(name))) 
     return; 
    if (!(entry = readdir(dir))) 
     return; 

    do { 
     if (entry->d_type == DT_DIR) { 
      char path[1024]; 
      if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) 
       continue; 
      printf("./%s\n", entry->d_name); 
      listdir(entry->d_name); 
     } 
     else 
      printf("./%s\n", entry->d_name); 
    } while (readdir(dir) != NULL); 
    closedir(dir); 
} 

int main(void) 
{ 
    listdir("."); 
    return 0; 
} 
+2

すべての警告とデバッグ情報([GCC](http://gcc.gnu.org/)を使用している場合は、gcc -Wall -g)を指定してコンパイルします。 **デバッガ**( 'gdb')を使用してください。あなたのfix-my-codeに関する質問は、話題にはならず、標準のCはディレクトリについて知りません(しかし、POSIXは)* linux *や* POSIX *のような他のタグを欠いています。 –

+2

単に返すのではなくエラーを報告するのは良い考えかもしれません... – Olaf

+0

'char * path [1024]'は、おそらくあなたが望むものではない 'char'ポインタの配列を割り当てます... – bejado

答えて

3

最初の問題は、あなたがreaddirの戻り値を放棄され、while条件である、それは、エントリに割り当てる必要があります。

また、再帰的にlistdirを呼び出すときは、パスの前に親の名前を追加する必要があります。それ以外の場合は、現在の作業ディレクトリから常に検索します。 このバージョンをお試しください:

void listdir(const char *name) { 
    DIR *dir; 
    struct dirent *entry; 
    int file_size; 

    if (!(dir = opendir(name))) 
      return; 

    while ((entry = readdir(dir)) != NULL) { // <--- setting entry 
      printf("%s/%s\n", name, entry->d_name); 
      if (entry->d_type == DT_DIR) { 
        char path[1024]; 
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) 
          continue; 
        sprintf(path, "%s/%s", name, entry->d_name); // <--- update dir name properly by prepend the parent folder. 
        listdir(path); 
      } 
    } 
    closedir(dir); 
} 

int main(void) 
{ 
    listdir("."); 
    return 0; 
} 
+1

あなたの早期リターンはオープンディレクトリ記述子をリークします。それは良いことではありません。 'do {...} while'ループは、質問と回答の両方において、完全に不適切です。 –

+0

右、dirはreturnの前に閉じなければなりません。ループも良いでしょう。 – fluter

2

以下は、コードに対する最小限の修正です。私はここで非標準のasprintfを使用する自由を取った。 glibcを使用していない場合は、代わりにsnprintfなどを使用してください。

特に、listdirに与えられたパスは、現在の作業ディレクトリからの完全な相対パスでなければなりません。または絶対パス。しかし、entry->d_nameのファイル名はファイルの基本名に過ぎません。したがって、それはlistdirに渡されたパスと連結されなければなりません。私はまた、不適切なdo ... whilewhileループに変更しました。

#define _GNU_SOURCE 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <string.h> 
#include <strings.h> 
#include <dirent.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 

void listdir(const char *path) { 
    DIR *dir; 
    struct dirent *entry; 

    if (!(dir = opendir(path))) 
     return; 

    while ((entry = readdir(dir))) { 
     if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) 
      continue; 

     char *current; 
     if (asprintf(&current, "%s/%s", path, entry->d_name) < 0) { 
      // asprintf failed 
      fprintf(stderr, "asprintf failed, exiting"); 
      goto exit; 
     } 

     puts(current); 
     if (entry->d_type == DT_DIR) { 
      listdir(current); 
     } 

     free(current); 
    } 

exit: 
    closedir(dir); 
} 

int main(void) 
{ 
    listdir("."); 
} 
関連する問題