简体   繁体   中英

How to copy a char into a char* vector

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM