2011-09-10 209 views
0

我是C++的新手,我有C#,Objective-C和JavaScript的經驗。函數返回數組C++

此刻,我試圖編寫一個函數,它接受一個路徑並返回一個目錄列表(該路徑中的所有文件和文件夾)。我在Ubuntu上做這個。

這裏是我到目前爲止的代碼,說實話,我努力理解雙指針語法以及它的實現,但是這是我的谷歌搜索導致我...

int FileManager::GetDirectoryListing(char *path, dirent **directoryEntries) 
{ 
    // Debug output... 
    printf("Listing directory at %s\n", path); 

    // Allocate memory for the directory entries 
    *directoryEntries = new dirent[MAX_FILES]; 

    // Open the path we were provided 
    DIR *directory = opendir(path); 

    // A counter of how many entries we have read 
    int entryCount = 0; 

    // Make sure we were able to open the directory 
    if(directory) { 

     printf("Successfully opened directory\n"); 

     // Read the first entry in the directory 
     struct dirent *directoryEntry = readdir(directory); 

     // While we have a directory entry 
     while(directoryEntry) { 

      // Debug output... 
      printf("%s\n", directoryEntry->d_name); 

      // Copy the directory entry to the array of directory entries we will return 
      memcpy(&directoryEntries[entryCount], directoryEntry, sizeof(struct dirent)); 

      // Increase our counter 
      ++entryCount; 

      // Read the next directory 
      directoryEntry = readdir(directory); 
     } 

     // Close the directory 
     closedir(directory); 
    } 

    return entryCount; 
} 

然後我打電話該功能通過:

dirent *directoryEntries = NULL; 

    int numberOfEntries = FileManager::GetDirectoryListing(deviceRootPath, &directoryEntries); 

    printf("File Manager returned directory listing.\n"); 

    for(int i = 0; i < numberOfEntries; ++i) { 

     printf("Looping through directory entries, at index: %i\n", i); 

     printf("%s\n", directoryEntries[i].d_name); 
    } 

它鎖起來,當它試圖訪問的第一個元素在directoryEntries即圍繞循環中的第一次。

我知道我不理解雙指針在幹什麼,我在GetDirectoryListing的調用之後我的腦海裏還沒有清晰的圖片說明directoryEntries的結構。

發生了什麼以及通過directoryEntries循環的正確方法是什麼?

回答

1
*directoryEntries = new dirent[MAX_FILES]; 

如果目錄數大於MAX_FILES,該怎麼辦?你怎麼知道它不能大於MAX_FILES

我認爲你應該使用std::vector<dirent>而不是dirent*。許多問題將得到解決。

我想實現的功能:

std::vector<dirent> FileManager::GetDirectoryListing(char *path) 
{ 
    std::vector<dirent> dirs; 
    DIR *directory = opendir(path); 
    if(directory) { 
     struct dirent *directoryEntry = readdir(directory); 
     while(directoryEntry) { 
      dirs.push_back(*directoryEntry); //push a copy of the original! 
      directoryEntry = readdir(directory); 
     } 
     closedir(directory); 
    } 
    return dirs; 
} 

現代編譯器將最有可能優化的代碼,避免返回值的副本。這種優化稱爲:

另外請注意,directories.size()會告訴你的條目數。因此,在調用點,你可以簡單地這樣做:

std::vector<dirent> dirs = FileManager::GetDirectoryListing(deviceRootPath); 
for(size_t i = 0; i < dirs.size() ; ++i) 
{ 
    std::cout << dirs[i].d_name << std:endl; 
} 

一般來說,喜歡std::cout超過printf,因爲後者並不安全!

+1

+1:std :: vector比手動管理的數組更容易使用。 – dreamlax

+0

@Jon:即使我幾乎立即刪除了這些行。 – Nawaz

+0

在C++ 11中,如果元素個數不變,你也可以使用'std :: array '。 – 2011-09-10 15:41:12

0

你的錯誤是在這一行:

 memcpy(&directoryEntries[entryCount], directoryEntry, sizeof(struct dirent)); 

directoryEntries是指針指向struct dirent。其中的每個條目都是指向struct dirent的指針。你的'&'會導致你複製到指針的地址,這不是你想要的。你想:

 memcpy(directoryEntries[entryCount], directoryEntry, sizeof(struct dirent)); 
2

此行

memcpy(&directoryEntries[entryCount], directoryEntry, sizeof(struct dirent)); 

,而不是這應該是:

memcpy(&(*directoryEntries)[entryCount], directoryEntry, sizeof(struct dirent)); 

或等價:

memcpy(*directoryEntries + entryCount, directoryEntry, sizeof(struct dirent)); 

的原因是directoryEntries是一個指針將指針轉換爲數組。在內存方面,它看起來像這樣:

        +------------+ 
directoryEntries --> array_head --> | dirents[0] | 
            +------------+ 
            | dirents[1] | 
            +------------+ 
            | dirents[2] | 
            +------------+ 
            | ...  | 

但是你喜歡directoryEntries對待它是一個指向數組的指針,它是不是:

WRONG!    +------------+ 
directoryEntries --> | dirents[0] | 
        +------------+ 
        | dirents[1] | 
        +------------+ 
        | ...  | 

所以你編寫出的將其綁定到您不屬於自己的內存中,從而導致未定義的行爲。

您需要額外級別的間接尋址的原因是因爲在C中,函數參數總是按值傳遞。爲了修改一個參數,你需要傳入一個指向原始值的指針,這就是你正在做的事情。你只需要記住,當處理那個指針時,你有一個額外的間接級別。

如果您使用的是C++而不是C,那麼使用引用參數代替指針會更好,您還應該使用std::vector<struct dirent>。您沒有額外的間接級別擔心,內存管理將自動處理。

+0

非常感謝您的詳細解釋和圖表,這就是爲什麼我喜歡Stack Overflow :)我對現在發生的事情有了更清晰的認識,謝謝! – Tyler