getting a list of files from a directory

Discussion in 'Mac Programming' started by farmerdoug, Apr 7, 2013.

  1. farmerdoug
    Expand Collapse
    macrumors 6502a

    Joined:
    Sep 16, 2008
    #1
    I am writing a routine to return a list of files in a directory in C. The routine takes the directory name and a maximum value for the number of files. I want it to be portable. And I'd like to get rid of the warning that **file_list is not initialized. Comments and help. thanks.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #define num_files 100
    void get_file_list( char * dir, char ** file_list);
    int main(int argc, const char * argv[])
    {
    
    	char **file_list, *dir;
    	
    	dir = (char *) calloc(25, sizeof(char));
    	file_list = (char **) calloc(25, sizeof(char*));
    	  
    	get_file_list(dir, file_list);
    	
    	
    	return 0;
    }
    
    
    void get_file_list( char * dir, char ** file_list)
    {
    
    	int i;
    	file_list = (char **) calloc(num_files, sizeof(char*));
    	for (i = 0; i < num_files; i++)
    		file_list[i]  = (char *) calloc(25, sizeof(char));
    		
    	//code
    
    
    }
    
     
  2. lloyddean
    Expand Collapse
    macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #2
    Are you asking for code to read a directory?

    I'm sure you'll find plenty of examples along the lines of ...

    Code:
    void listdir(char* dir)
    {
        struct dirent*  pdirent;
        DIR*                pdir        = opendir(dir);
        if ( pdir )
        {
            while ((pdirent = readdir(pdir)) != NULL)
            {
                if ( ! strcmp(pdirent->d_name, ".") || ! strcmp(pdirent->d_name, "..") )
                {
                    /* don't bother showing parent or current directory */
                    continue;
                }
    
                printf("%s/%s\n", dir, pdirent->d_name);
            }
    
            closedir(pdir);
    
            return;
        }
    
        fprintf(stderr, "listdir: can't open %s\n", dir);
    }
    
    ... that you can adapt to your purposes.
     
  3. farmerdoug
    Expand Collapse
    thread starter macrumors 6502a

    Joined:
    Sep 16, 2008
    #3
    Actually, I was more interested in how I should allocate memory and pass pointers back and forth. The code you sent, which is actually very helpful because it teaches me about calls I was aware of, doesn't help me see how best to that. I need a list of files in the directory.
     
  4. lloyddean, Apr 7, 2013
    Last edited: Apr 7, 2013

    lloyddean
    Expand Collapse
    macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #4
    Well without much thought and the restriction that the directory being traversed is static and will not change during the running of the program -

    Code:
    int get_file_list(char* pszDirectoryName, char** ppsz)
    {
        int             entries_count   = 0;
    
        struct dirent*  pdirent;
        DIR*            pdir;
    
        pdir = opendir(pszDirectoryName);
        if ( pdir )
        {
            while ( (pdirent = readdir(pdir)) )
            {
                if ( ! strcmp(pdirent->d_name, ".") || ! strcmp(pdirent->d_name, "..") )
                {
                    /* don't bother show parent or current directory */
                    continue;
                }
    
                if ( ppsz )
                {
                    char* psz = (char*)calloc(strlen(pdirent->d_name) + 1, sizeof(char));
                    strcpy(psz, pdirent->d_name);
    
                    ppsz[entries_count] = psz;
                }
    
                entries_count++;
            }
    
            closedir(pdir);
    
            return entries_count;
        }
    
        return 0;
    }
    
    int main(void)
    {
        int entries_count   = get_file_list("/", NULL);
        char** ppsz         = (char**)calloc(entries_count, sizeof(char*));
        entries_count       = get_file_list("/", ppsz);
    
        for (int i = entries_count; i--; )
        {
            printf("%s\n", ppsz[i]);
    
            free((void*)ppsz[i]);
        }
    
        free((void*)ppsz);
    
        return EXIT_SUCCESS;
    }
    
     
  5. robvas
    Expand Collapse
    macrumors 68000

    Joined:
    Mar 29, 2009
    Location:
    USA
    #5
    Doug:

    I'm going to suggest again you use a language like Python or Ruby for your tasks. You can do something like this in a one-liner:
    Code:
     dir_contents = Dir.entries("/absolute/path/to/directory")
     
  6. Senor Cuete
    Expand Collapse
    macrumors regular

    Joined:
    Nov 9, 2011
    #6
    free()

    You need to balance your calls to calloc() with free() or you will have memory leaks.
     
  7. farmerdoug
    Expand Collapse
    thread starter macrumors 6502a

    Joined:
    Sep 16, 2008
    #7
    Leaks.
    In the main code, if I call the routine more than once. Yes. Thanks.
     
  8. lloyddean
    Expand Collapse
    macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #8
    As I said I threw it together without much thought.

    As well you're presuming my motive is to provide Doug with well written software and I can assure you it's not. I'm simply trying to get him to "Think Different" not do his work for him.
     
  9. farmerdoug
    Expand Collapse
    thread starter macrumors 6502a

    Joined:
    Sep 16, 2008
    #9
    Lloyd,
    I've really been trying to clean up my act. That's why the orignal question was more about passing pointers in the proper manner than writing the read directory code, as I said.
     
  10. lloyddean, Apr 8, 2013
    Last edited: Apr 8, 2013

    lloyddean
    Expand Collapse
    macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #10
    The same thing done in C++ mixed with C.

    Note the use of STL containers 'string' and 'vector' handling all memory allocation/deallocation for you!

    Again threw it together with little thought other than showing the utility of C++ and the STL to simplify programming tasks such as yours.

    Code:
    #include <cstdlib>
    
    #include <iostream>
    #include <string>
    #include <vector>
    
    #include <dirent.h>
    
    typedef std::vector<std::string>            svec_t;
    typedef std::vector<std::string>::iterator  svec_itr;
    
    void GetDirContnets(const char* pszDirectoryName, svec_t& svec)
    {
        DIR* pdir = opendir(pszDirectoryName);
        if ( pdir )
        {
            struct dirent*  pdirent;
    
            while ( (pdirent = readdir(pdir)) )
            {
                if ( strcmp(pdirent->d_name, ".") && strcmp(pdirent->d_name, "..") )
                {
                    svec.push_back(pdirent->d_name);
                }
            }
    
            closedir(pdir);
        }
    }
    
    int main(void)
    {
        svec_t  svec;
        GetDirContnets("/", svec);
    
        for ( svec_itr itr = svec.begin(); itr != svec.end(); itr++ )
        {
            cout << *itr << "\n";
        }
    
        return EXIT_SUCCESS;
    }
     
  11. subsonix
    Expand Collapse
    macrumors 68040

    Joined:
    Feb 2, 2008
    #11
    Assuming the question is about resource management. It would probably be better to do all allocation in your get_* function as opposed to doing it in two places. Just return a new list or NULL on failure. Also, since you are allocating for each directory entry string manually, there is no need to restrict yourself to 25 characters, allocate strlen +1 or use strdup.

    Finally create a corresponding free_* function to free the entire list in one go.
     
  12. lloyddean
    Expand Collapse
    macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #12
    I'm simply trying to get him to reconsider his contortionist memory allocation and parameter passing monstrosities as being complex, mind numbing and totally unnecessary.
     
  13. Senor Cuete
    Expand Collapse
    macrumors regular

    Joined:
    Nov 9, 2011
    #13
    Even once.
     

Share This Page