Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
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


}
 

lloyddean

macrumors 65816
May 10, 2009
1,047
19
Des Moines, WA
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.
 

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
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.
 

lloyddean

macrumors 65816
May 10, 2009
1,047
19
Des Moines, WA
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;
}
 
Last edited:

robvas

macrumors 68040
Mar 29, 2009
3,240
629
USA
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")
 

Senor Cuete

macrumors 6502
Nov 9, 2011
423
30
free()

You need to balance your calls to calloc() with free() or you will have memory leaks.
 

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
Leaks.
In the main code, if I call the routine more than once. Yes. Thanks.
 

lloyddean

macrumors 65816
May 10, 2009
1,047
19
Des Moines, WA
You need to balance your calls to calloc() with free() or you will have memory leaks.

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.
 

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
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.
 

lloyddean

macrumors 65816
May 10, 2009
1,047
19
Des Moines, WA
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;
}
 
Last edited:

subsonix

macrumors 68040
Feb 2, 2008
3,551
79
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.
 

lloyddean

macrumors 65816
May 10, 2009
1,047
19
Des Moines, WA
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.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.