我是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
的正确方法是什么?
答案 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));