getting a list of files from a directory

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

  1. 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. 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. 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

    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. 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. 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. 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. 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. 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

    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. 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. 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. macrumors regular

    Joined:
    Nov 9, 2011
    #13
    Even once.
     

Share This Page