reading multiple file names & displaying them

This is a discussion on reading multiple file names & displaying them within the C++ Programming forums, part of the General Programming Boards category; hi, wondering if someone could explain why the following doesn't work as intended ? The 2nd for loop should display ...

  1. #1
    Registered User
    Join Date
    Apr 2008
    Location
    Australia
    Posts
    55

    reading multiple file names & displaying them

    hi,
    wondering if someone could explain why the following doesn't work as intended ?
    The 2nd for loop should display the file names, but instead it displays the same one, the last one read in.
    Now I've tested reading in strings into char array and displaying them again in another for loop, and it works as intended, and I've looked/compared the addresses too but this, has me stumped.

    Something I'm missing?



    Code:
    #include <dirent.h> 
    #include <iostream>
    using namespace std;
    
    int main()
    {
    char *afilelist[100] = { "0" };
    DIR  					*d;
    struct dirent *dir[100];
    d = opendir(".");
    
    if (d)
    {
    	for( int x=0; (dir[x] = readdir(d)) != NULL;x++)
    	{
    		afilelist[x] = dir[x]->d_name;
    		cout<<afilelist[x]<<endl; //displays file names properly.
    	}
    closedir(d);
    }
    
    cout<<endl;
    for( int x=0;x<10 ; x++)
    {
    	cout<<afilelist[x]<<endl; //doesn't display file names as per the array ?
    }
    
    cin.get();
    }

  2. #2
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Katy, Texas
    Posts
    2,309
    Perhaps the system returned pointer for dir[x]->d_name is the same on each call? Print out name and address in your first FOR loop as it runs to see.
    Mac and Windows cross platform programmer. Ruby lover.

    Quote of the Day
    12/20: Mario F.:I never was, am not, and never will be, one to shut up in the face of something I think is fundamentally wrong.

    Amen brother!

  3. #3
    Registered User
    Join Date
    Apr 2008
    Location
    Australia
    Posts
    55
    If I run the code & return the addresses (and what it returns, is next to it);

    First for loop;
    0x22fd70 .
    0x22fd74 ..
    0x22fd78 file1name.txt
    0x22fd7c file2name.txt
    0x22fd80 fileXname.ext
    0x22fd84 fileLast.ext

    2nd for loop, the addresses are the same as first, however what it returns is not
    0x22fd70 fileLast.ext
    0x22fd74 fileLast.ext
    0x22fd78 fileLast.ext
    0x22fd7c fileLast.ext
    It's only displaying/showing the last read in file name.

    Now if I do this with some simple char/string array and do the same thing, I don't have the same problem. So I don't understand why the problem is happening with this code.

  4. #4
    Registered User
    Join Date
    Apr 2006
    Posts
    2,050
    Looks like you need to copy the directory names into an array of strings, instead of keeping a pointer. I recommend using an array of std::string instead of char *.

    Also, while 100 is surely a high enough for any reasonable use of the program, you should still make the program well defined if the user input is not what you expect, namely that there are more than 100 files in the directory. Better predictable, though limited use behavior, than an uncontrolled crash. In this case that means adding a check for x<100 for the first for loop.

    By the way: this does not do what you think:
    Code:
    char *afilelist[100] = { "0" }
    It makes a single pointer that points to the string "0", and the rest are null pointers.
    Last edited by King Mir; 11-08-2009 at 03:57 PM.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  5. #5
    Registered User
    Join Date
    Apr 2008
    Location
    Australia
    Posts
    55
    Quote Originally Posted by King Mir View Post
    ....while 100 is surely a high enough....
    My code is just for my own testing/learning.


    Looks like you need to copy the directory names into an array of strings, instead of keeping a pointer. I recommend using an array of std::string instead of char *.
    Thanks, changing that worked. However, could you/someone possibly explain why the above code doesn't work as intended but the following does;

    Code:
    #include <iostream>
    using namespace std;
    
    int main()
    {
    	char *aChar[15] = { "0" };
    	char *cString[] = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "end" };
    
    for(int i=0; cString[i]<"end" ; i++)
    {
    	aChar[i] = cString[i];
    }
    
    for(int i=0; cString[i]<"end"; i++)
    {
    	cout<<aChar[i]<<endl; //displays array as intended
    }
    
    cin.get();
    }

  6. #6
    Registered User
    Join Date
    Oct 2009
    Location
    While(1)
    Posts
    377
    Use strcmp in a while loop like strcmp("end", cString[i]) != 0

  7. #7
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Katy, Texas
    Posts
    2,309
    If you look at the addresses returned from the readdir() function you posted above, they are only 4 bytes apart. Apparently, readdir() on your system does not guarantee to preserve the contents of the structure across subsequent calls.

    And, tell me you realize that this:
    Code:
    for(int i=0; cString[i]<"end" ; i++)
    is comparing the addresses and not the values.

    This works on my system (a Mac). See how it runs on yours.
    Code:
    #include <dirent.h> 
    #include <iostream>
    using namespace std;
    
    int main()
    {
    int x, y ; 
    struct dirent * afilelist[100] ; // "0" };
    DIR *d;
    struct dirent * dir[100];
    d = opendir("..");
    
    if (d)
    {
    	for( x=0; (dir[x] = readdir(d)) != NULL; x++)
    	{
    		// afilelist[x] = dir[x]->d_name;
    		afilelist[x] = dir[x] ; 
    
    		cout << afilelist[x] -> d_name << endl; //displays file names properly.
    		if (x > 0) cout << "\tPrevious name was " << afilelist[x-1] -> d_name << endl ; 
    		if (x > 1) cout << "\tPrevious previous name was " << afilelist[x-2] -> d_name << endl ; 
    	}
    closedir(d);
    }
    
    cout<<endl;
    for( y=0; y < x ; y++)
    {
    	cout << afilelist[y] -> d_name << endl; //doesn't display file names as per the array ?
    }
    
    cin.get();
    }
    Mac and Windows cross platform programmer. Ruby lover.

    Quote of the Day
    12/20: Mario F.:I never was, am not, and never will be, one to shut up in the face of something I think is fundamentally wrong.

    Amen brother!

  8. #8
    Registered User
    Join Date
    Apr 2008
    Location
    Australia
    Posts
    55
    Quote Originally Posted by Dino View Post
    If you look at the addresses returned from the readdir() function you posted above, they are only 4 bytes apart. Apparently, readdir() on your system does not guarantee to preserve the contents of the structure across subsequent calls.

    This works on my system (a Mac). See how it runs on yours.

    Works on mine, but again the 2nd for loop only displays the last or most recent filename read in.


    Code:
    for(int i=0; cString[i]<"end" ; i++)
    is comparing the addresses and not the values.

    Really? But if one displays what cString[i] is, it shows/returns the value yes? How is that comparing addresses if "end" is a string literal?

    Thanks.

  9. #9
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Katy, Texas
    Posts
    2,309
    To compare strings, you use strcmp().
    Mac and Windows cross platform programmer. Ruby lover.

    Quote of the Day
    12/20: Mario F.:I never was, am not, and never will be, one to shut up in the face of something I think is fundamentally wrong.

    Amen brother!

  10. #10
    Registered User
    Join Date
    Apr 2006
    Posts
    2,050
    Quote Originally Posted by Tropod View Post
    Really? But if one displays what cString[i] is, it shows/returns the value yes? How is that comparing addresses if "end" is a string literal?

    Thanks.
    It is returning the value -- of the char pointer.

    A char pointer can be treated like a string; most functions that take or return a char pointer assume that it points to a null terminated set of characters used for input and output. But at the end of the day it's still a pointer to char. If you compare pointers, you are comparing memory locations.

    Arrays, including string literals, will decay to pointers in the context of any operator except & (address of).
    Last edited by King Mir; 11-09-2009 at 03:51 PM.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. File transfer- the file sometimes not full transferred
    By shu_fei86 in forum C# Programming
    Replies: 13
    Last Post: 03-13-2009, 12:44 PM
  2. Reading File Names
    By Thrack in forum C++ Programming
    Replies: 5
    Last Post: 03-27-2007, 05:08 PM
  3. Encryption program
    By zeiffelz in forum C Programming
    Replies: 1
    Last Post: 06-15-2005, 03:39 AM
  4. Unknown Memory Leak in Init() Function
    By CodeHacker in forum Windows Programming
    Replies: 3
    Last Post: 07-09-2004, 09:54 AM
  5. what does this mean to you?
    By pkananen in forum C++ Programming
    Replies: 8
    Last Post: 02-04-2002, 02:58 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21