-1

The exact problem that I am having is that we were assigned to make a program that had 2 command line arguments, both being text files. The code that I have for arg[1] works fine, it reads in the text file and stores it into an array. Once it is stored into the array called key it goes through a loop that only leaves alpha characters and makes uppercase change to lowercase. Once again this works fine when i test it and print out the final array called key. When I use the same code for arg[2] the first loop (while(!feof(file2))) does not even copy the contents of the other text file into the array called plain correctly. It copies all the content but adds ▒ at the end when i print out the plain array to test to see if I have all the characters in there before running it through the loop that only leaves alphacharacters in it. If I switch the order of the files when I enter them in the terminal then the second file works fine with the arg[1] code but then the other file does not work with the arg[2] code. I'm using mobaxterm so I enter it like "./a.out k1.txt p1.txt" without the quotations of course. I also commented out the code that strips the nonalpha characters in arg[2] just to try and figure out why the while loop before it is not storing the file contents correctly.

Here are the contents of the text files

k1.txt (instead of a space imagine it goes to the next line):

bbbbbbbbb bbbbbbbbb bbbbbbbbb bbbbbbbbb bbbbbbbbb bbbbbbbbb bbbbbbbbb bbbbbbbbb

p1.txt:

"If you find that you're spending almost all your time on theory, start turning some attention to practical things; it will improve your theories. If you find that you're spending almost all your time on practice, start turning some attention to theoretical things; it will improve your practice." - Donald Knuth

This is an encryption assignment by the way and k1 is the key and p1 is the plain text.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int main(int argc, char **argv) {

    printf( "\ncommandline arguments including program name:\n\n");
    int i;
    for ( i = 0; i < argc; i++ ) {
                      printf( "argument %d: %s\n", i, argv[ i ] );
    }
    printf( "\n");

    char* fname = argv[ 1 ];
    FILE *file = fopen( fname, "r" );
    char key[512];
    int x,y, z=0;

    if ( file == 0 )
    {
                      printf( "Could not open file\n" );
    } else {
                      printf( "File opened successfully\n" );

                      while(!feof(file))
                         {
                            fscanf(file, "%c", &key[z]);
                            z++;
                         }fscanf(file, "%c", &key[z]);

                            for(x=0; key[x] != '\0'; x++)
                            {
                               while(!((key[x] >= 'a' && key[x] <= 'z') || (key[x] >= 'A' && key[x] <= 'Z') || key[x] == '\0'))
                               {
                                  for(y=x; key[y] != '\0'; ++y)
                                     {
                                        key[y]=key[y+1];
                                     }
                                  key[y] = '\0';
                               }
                               key[x] = tolower(key[x]);
                            }

                            printf("Key text:\n%s\n", key);
                            fclose( file );
    }

    char* fname2 = argv[ 2 ];
    FILE *file2 = fopen( fname2, "r" );
    char plain[512];
    int j,k, l=0;


    if ( file2 == 0)
    {
       printf("Could not open file\n");
    }else {
       printf("File opened successfully\n");

                      while(!feof(file2))
                         {
                            fscanf(file2, "%c", &plain[l]);
                            l++;
                         }fscanf(file2, "%c", &plain[l]);
                           /* for(j=0; key[j] != '\0'; j++)
                            {
                               while(!((plain[j] >= 'a' && plain[j] <= 'z') || (plain[j] >= 'A' && plain[j] <= 'Z') || plain[j] == '\0'))
                               {
                                  for(k=j; plain[k] != '\0'; ++k)
                                     {
                                       plain[k]=plain[k+1];
                                     }
                                  plain[k] = '\0';
                               }
                               plain[j] = tolower(plain[j]);
                            }*/

                            printf("Plain text:\n%s\n", plain);
                            fclose(file2);
    }


return 0;
}
  • 1
    [why-is-while-feof-file-always-wrong](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong). – H.S. Jun 24 '18 at 01:48

1 Answers1

1

feof

Check end-of-file indicator Checks whether the end-of-File indicator associated with stream is set, returning a value different from zero if it is.

This indicator is generally set by a previous operation on the stream that attempted to read at or past the end-of-file.

Notice that stream's internal position indicator may point to the end-of-file for the next operation, but still, the end-of-file indicator may not be set until an operation attempts to read at that point. [emphasis mine]

Now, lets see the how this loop will work:

                      while(!feof(file))
                     {
                        fscanf(file, "%c", &key[z]);
                        z++;
                     }fscanf(file, "%c", &key[z]);

Assume that fscanf() has read the last character of file. After this, the stream internal position indicator is pointing to EOF but feof() will return 0 because there is no read operation attempted on the stream which will set the end-of-file indicator. Hence the control go inside the loop and fscan() will attempt to read from file. Since EOF is reached, fscan() will set the end-of-file indicator. Now the EOF is set, so the feof() will return non-zero value and loop will end. Hence, the way you are using feof(), you will always have this extra iteration of while loop.
After encountering EOF, you are still trying to read from stream file:

fscanf(file, "%c", &key[z]);

Here, also fscanf() will return the EOF because there is nothing remain to read from stream file. This statement is meaning less.

In C, strings are actually one-dimensional array of characters terminated by a null character \0. fscanf() does not automatically append null character at the end when you read from stream using %c format specifier. So, the character array key and plain does not have null character at the end of characters read and if you try to print them using %s, you may get some junk character's in the output.

You can do:

while ((ret = fscanf(file, "%c", &key[z])) != EOF) {
    z++;
}
key[z] = '\0';

You can also read the string of characters from file using %s format specifier, like this:

fscanf(file, "%511s", key);

With %s format specifier you dont need loop and a terminating null character is automatically added at the end of the stored sequence.

It is good to add check for max character modifier that is 1 less than the length of the input buffer (which is 511, in your case).

Alternatively, you can also use fgets() to read from file.


Check this:

while ( !feof (file) ) is always wrong?
Reading from file using fgets

H.S.
  • 11,654
  • 2
  • 15
  • 32