从函数C ++返回数组

时间:2011-09-10 05:18:23

标签: c++ c arrays pointers

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

目前我正在尝试编写一个获取路径并返回目录列表的函数(该路径中的所有文件和文件夹)。我在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中的第一个元素时,即在第一次循环时,它会锁定。

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

正在发生什么以及循环通过directoryEntries的正确方法是什么?

3 个答案:

答案 0 :(得分: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>。您不必担心额外的间接级别,并自动为您处理内存管理。

答案 1 :(得分: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,因为后者不安全!

答案 2 :(得分:0)

你的错误在于这一行:

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

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

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