I am using dirent to read filenames from a specific folder, and I want to save the names in a char* vector. It seems that it's copying some weird symbols instead of copying the filenames. This is what I tried so far:
std::vector<char*> filenames;
int filenamesAndNumberOfFiles(char *dir)
{
struct dirent *dp;
DIR *fd;
int count = 0;
if ((fd = opendir(dir)) == NULL)
{
fprintf(stderr, "listdir: can't open %s\n", dir);
return 0;
}
while ((dp = readdir(fd)) != NULL)
{
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue; /* skip self and parent */
printf("Filename: %s\n", dp->d_name);
filenames.push_back(dp->d_name);
count++;
}
closedir(fd);
return count;
}
Can anyone tell me why it doesn't copy the filenames and how could I do to copy them?
Edit: d_name is a char variable declared as:
char d_name[PATH_MAX];
and it seems like in my program PATH_MAX is equal to 260.
PS: It is my first time when I use dirent, so I am not really familiar with it.
Replace std::vector<char*>
with std::vector<std::string>
. And add #include <string>
. That should solve the problem.
It seems that you haven't yet grasped the concept of pointers and arrays in C/C++, and I'm not sure if explaining that fits within the limits of an SO answer. But this answer might be of use: C++ : Does char pointer to std::string conversion copy the content?
In short, the problem with your code is that instead of copying the memory where string is stored (the characters themselves, char[PATH_MAX]
), you were only copying a pointer to that memory ( char*
). And the memory block pointed to was later reused or even deleted, leaving your stored pointer invalid.
You need to store copies of the string. Use vector<string>
. When you push_back(dp->d_name)
you are storing a dangling pointer, because dp
goes out of scope after the function ends.
This is because you push a pointer, dp->d_name
onto the vector, however the string this pointer points to is gone when you call the next readdir()
call.
Instead, you must make a copy of that string, and push it onto the vector:
filenames.push_back(strdup(dp->d_name));
Now, you must remember to free() this string that is copied into the vector when you are done with your filenames
vector
However, please don't do this at all. Just use:
std::vector<std::string> filenames;
And you can use your original code here, and the memory management will be taken care of.
As user2079303 said a second call to readdir will overwrite the results returned by the first call ( link ).
But I would recommend you to use a string for this in C++:
std::vector<std::string> filenames;
int filenamesAndNumberOfFiles(char *dir)
{
struct dirent *dp;
DIR *fd;
int count = 0;
if ((fd = opendir(dir)) == NULL)
{
fprintf(stderr, "listdir: can't open %s\n", dir);
return 0;
}
while ((dp = readdir(fd)) != NULL)
{
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue; /* skip self and parent */
printf("Filename: %s\n", dp->d_name);
filenames.push_back( std::string(dp->d_name) );
count++;
}
closedir(fd);
return count;
}
You can always use c_str()
if you need a char*
later on.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.