2011-09-10 170 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