1

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!

PluffTed
  • 53
  • 5
  • The header files `unistd.h` and `dirent.h` are not part of ISO C. This means that you are using platform-specific extensions. There is nothing wrong with that, but when you do this, please also specify the platform in your question, by setting the appropriate tag. As far as I can tell, the flag "posix" would probably be appropriate in this case. – Andreas Wenzel Jul 01 '20 at 19:36
  • You should definitely *not* fclose(entry_file) outside the else clause where it is opened. (that is, move fclose inside the else). You can catch this sort of error by limiting the scope of the variable. (ie, move its declaration into the block in which it is used) – William Pursell Jul 01 '20 at 19:38
  • Check your code, `fclose( entry_file );` should be in the if – Ôrel Jul 01 '20 at 19:42
  • Thanks guys! Unfortunately, it does not work still :( The program runs but nothing is printed out after placing the fclose( entry_file ); inside of the else loop [and just outside of if ( entry_file != NULL ) – PluffTed Jul 01 '20 at 20:10
  • Replace `printf( "Unable to read directory!" );` with `perror(path);` Error messages should be informative and written to stderr. – William Pursell Jul 01 '20 at 20:19

1 Answers1

0

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);
}
Ôrel
  • 7,044
  • 3
  • 27
  • 46
  • Hey Orel thank you so much for your time! So your function here prints out the names of the 3 .txt files I have placed in the input directory, but the contents of the files are still not printing :( Did this functionality work on your own end? Again, really appreciate the time :) – PluffTed Jul 01 '20 at 21:01
  • yes it is working for me, the stdout stream is line buffered by default, add a new line char to flush the buffer can help. I have edited the code and add a `putchar` – Ôrel Jul 01 '20 at 21:10
  • Something else worth noting is that when I try to altered this just now to print out a file's name AFTER using fopen() on each file, the file names do not even print at all, so something weird is happening when I attempt to use fopen() it seems like – PluffTed Jul 01 '20 at 21:11
  • What is your platform ? Try to print using stderr `fprintf(stderr, "...` – Ôrel Jul 01 '20 at 21:14
  • I made this modification and still nothing is printing :( I am using an ubuntu linux terminal in a virtualbox...is this a problem for any of these c header files you think? – PluffTed Jul 01 '20 at 21:21
  • So I found the problem but I am having problems figuring out why it is happening. I used your fprintf(stderr, "Error") inside of the if (entry_file == NULL) loop and I WAS receiving these printed out "Errors"....why is entry_file = fopen( in_file->d_name, "r" ) resulting in a NULL FILE pointer every time ? – PluffTed Jul 01 '20 at 21:43
  • I have added an error output for fopen to have detail on the error. Perhaps a file permission issue – Ôrel Jul 01 '20 at 21:51
  • Thank you!! The specific error is "Error opening file: No such file or directory", but I just checked the permissions of each file and there are no restrictions. I'm so sorry this is such a hard problem right now!! :_( – PluffTed Jul 01 '20 at 22:06
  • I know!! you need the path to the file not only the filename, I have added it, look at `filepath` in the code – Ôrel Jul 01 '20 at 22:44
  • WORKED!!! You are seriously the greatest I can't tell you how much of a headache you saved me from. I guess I will always just never fopen() on dirent d_name 's to avoid the pain – PluffTed Jul 01 '20 at 23:02