Search code examples
cfopenreaddiropendirgetc

Reading only .txt files from an input directory, then getc all contents into one array in C


So I am attempting to make a function that receives an input directory, examine only its ".txt" files and then store ALL contents into one character array (dynamically allocated, here). As I use getc() on every character in each file, one at a time, I am not only storing each character at a time, but I want them to printf() one at a time as well just to see if all the files are being read correctly. Please make note that everything within the else loop here worked 100% correctly on only reading a single input file in another program I made.

This is alphabetcount.c, which is just the function...

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include<unistd.h> 
#include <stdbool.h>
#include <dirent.h>
#include "count.h"

void alphabetlettercount( char *path, char *filetowrite, long alphabetfreq[] )
{
    DIR *dir;
    FILE *entry_file;
    struct dirent *in_file;

    int c, i;
    int filled_elements = 0;

    char *temp_arrayPointer;
    char *perm_arrayPointer;

    perm_arrayPointer = ( char* ) calloc ( 1, sizeof( char ) );

    dir = opendir( path );

    if( dir == NULL )
    {
        printf( "Unable to read directory!" );
        exit( 1 );
    }

    while( ( in_file = readdir( dir ) ) != NULL )
    {

        if ( !strcmp ( in_file->d_name, "." ) || !strcmp ( in_file->d_name, ".." ) || strstr( ( in_file->d_name ), ".txt" ) )
        {

        }


       else
       {

            printf( "%s\n", in_file->d_name );

            entry_file = fopen( in_file->d_name, "r" );

            if ( entry_file != NULL )
            {

                while ( ( c = getc( entry_file ) ) != EOF )
                {
                        *( perm_arrayPointer + filled_elements ) = c;

                        printf( "%c", ( *( perm_arrayPointer + filled_elements ) ) );

                        filled_elements++;        

                        temp_arrayPointer = ( char* ) realloc ( perm_arrayPointer, ( ( filled_elements + 1 ) * sizeof( char ) ) );

                        if ( temp_arrayPointer != NULL )
                        {
                            perm_arrayPointer = temp_arrayPointer;
                        }
            }

        }

        fclose( entry_file );    
    }

    closedir( dir );    
}

And this is testingalphabetcount.c, or just simply the main()...

(NOTE: alphabetlettercount() prototype is present in the count.h #include file in both .c files)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include<unistd.h> 
#include <stdbool.h>
#include <dirent.h>
#include "count.h"

int main()
{

      char *path = "../data";           // the data *.txt files are under this folder
      
      alphabetlettercount(path);  // process the data files

}

The output to this is...

.
.
..
..

...if the " printf("%s\n", in_file->d_name ); " is placed inside the "If" loop, but if this is instead placed inside the "else" loop, my output is...

test2.txt 
Segmentation Fault

Any suggestions as to what I am doing wrong? I think it has something to do with fopen() being used incorrectly? Thanks and sorry for the long read!


Solution

  • I have changed your function alphabetlettercount to match the main function provided

    I have simplified your else by using continue this avoid a too big depth and facilitate the reading.

    I have move the variables in the dedicated scope. I have tried to keep your style but some lines are quite long IMHO.

    You shouldn't cast calloc (or malloc) return.

    The main issue on your code was the position of fclose and your test to get only .txt file (I have just added the missing !, note that foo.txt.bar will be read)

    Doing so many realloc is not a good practice, try to allocate a 1k buffer and double this size each time needed can be better

    static void alphabetlettercount(const char *path)
    {
        DIR *dir;
        struct dirent *in_file;
    
        int filled_elements = 0;
    
        char *perm_arrayPointer;
    
        perm_arrayPointer = calloc ( 1, sizeof( char ) );
    
        dir = opendir( path );
    
        if( dir == NULL )
        {
            printf( "Unable to read directory!" );
            exit( 1 );
        }
    
        while( ( in_file = readdir( dir ) ) != NULL )
        {
            FILE *entry_file;
            int c;
            char filepath[256];
            if ( !strcmp ( in_file->d_name, "." ) || !strcmp ( in_file->d_name, ".." ) || !strstr( ( in_file->d_name ), ".txt" ) )
            {
                continue;
            }
    
            printf( "%s\n", in_file->d_name );
            snprintf(filepath, sizeof(filepath), "%s/%s", path, in_file->d_name );
            entry_file = fopen( filepath, "r" );
            if ( entry_file == NULL ) {
                printf ("Error opening file: %s\n",strerror(errno));
                continue;
            }
    
            while ( ( c = getc( entry_file ) ) != EOF )
            {
                char *temp_arrayPointer;
                *( perm_arrayPointer + filled_elements ) = c;
    
                printf( "%c", ( *( perm_arrayPointer + filled_elements ) ) );
    
                filled_elements++;
    
                temp_arrayPointer = realloc ( perm_arrayPointer, ( ( filled_elements + 1 ) * sizeof( char ) ) );
    
                if ( temp_arrayPointer != NULL )
                {
                    perm_arrayPointer = temp_arrayPointer;
                }
            }
            putchar('\n');
            fclose( entry_file );
        }
    
        closedir( dir );
        free(perm_arrayPointer);
    }