从函数C++返回数组

Return array from function C++

本文关键字:数组 返回 C++ 函数      更新时间:2023-10-16

我是C++的新手,我有C#、Objective-C和JavaScript的经验。

目前,我正在尝试编写一个函数,它采用一个路径并返回一个目录列表(该路径上的所有文件和文件夹(。我在Ubuntu上做这件事。

到目前为止,这是我的代码,老实说,我很难理解双指针语法及其实现的目标,但这正是我在谷歌上搜索的结果…

int FileManager::GetDirectoryListing(char *path, dirent **directoryEntries)
{
    // Debug output...
    printf("Listing directory at %sn", 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 directoryn");
        // Read the first entry in the directory
        struct dirent *directoryEntry = readdir(directory);
        // While we have a directory entry
        while(directoryEntry) {
            // Debug output...
            printf("%sn", 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: %in", i);
        printf("%sn", directoryEntries[i].d_name);
    }

当它试图访问directoryEntries中的第一个元素时,即第一次访问循环时,它处于锁定状态。

我知道我不明白双指针在做什么,在调用GetDirectoryListing之后,我对directoryEntries的结构也没有清晰的了解。

发生了什么,通过directoryEntries循环的正确方式是什么?

此行

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>。您不需要担心额外级别的间接性,内存管理是自动为您处理的。

*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;
}

现代编译器很可能会优化此代码,以避免复制返回值。这种优化被称为:

  • 返回值优化(RVO((或命名RVO(

还要注意,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,因为后者不安全!

您的错误在这一行:

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

您的directoryEntries是指向struct dirent的指针。其中的每个条目都是指向struct dirent的指针。您的"&"导致您复制到指针的地址,而这不是您想要的。您想要:

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