0

I am having a problem with writing from one file to another, especially the last value, which is end of file, prints out as question mark in a black square.

My code is supposed to replace text on some conditions which works perfectly just the last value which is EOF is making a little problem.

Any ideas?

input file

Hi, this is *list* version v2.
Contains 8 words. 123

output file

___, _____ ___ *_____* _____ ___.
_____ ___ _____. ___�

C source file

int main()
{
    FILE *li, *sa;

    li = fopen("list.txt", "r");
    sa = fopen("sablona.txt", "w");

    int c, poc = 0;
    char a[3] = "___"; 
    char b[5] = "_____";

    while ( ! feof(li) > 0 ) {

        c = getc(li);

        if ( isalnum(c) )
            poc++;
        else if ( poc > 0 && poc < 4 ) {
            fputs(a, sa);
            poc = 0;
        }
        else if ( poc >= 4 ) {
            fputs(b, sa); 
            poc = 0;
        }

        if ( ! isalnum(c) )
            putc(c, sa);
    }

    fclose(li);
    fclose(sa);

    return 0;
}
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • 2
    You have buffer overflow in your `a` and `b` arrays, as you don't make space for the string terminator. – Some programmer dude Feb 21 '15 at 18:08
  • 3
    Also, don't use e.g. `while (!feof(li))`, it will in most occasions not work as expected. The reason is that the `EOF` flag is not set until *after* you read from beyond the end of the file. Instead use e.g. `while ((c = getc(li)) != EOF)`. – Some programmer dude Feb 21 '15 at 18:10
  • 1
    I was using what you just suggested but then last string, in my file it is 123 did not appear at all in output file. That is why I changed it to feof and now I get questionmark instead. .. Can you please provide a code? – user3294564 Feb 21 '15 at 18:23
  • The question-mark is probably *because* your loop condition, because when you reach the end of the file the `EOF` flag will not be set, it will not be set until the next time you use `getc` to read the next character, and then the `EOF` flag will be set and `getc` will return `EOF` which you do not check for and then you print it. The difference between your current loop and the one I suggest (where you do the `getc` call as a part of the loop condition) is that your code does not check for `EOF` properly, while my suggestion do. The rest of the code should be just the same. – Some programmer dude Feb 21 '15 at 18:42
  • 1
    I am pretty sure that it cannot work because I changed it back as you suggested and it does not work properly. In output file, I am missing last three underscores. It all ends just with _____. If I make a new line in source file then it prints out as I want it but I need it to work even when there is EOF right after last visible character in my source file. – user3294564 Feb 21 '15 at 18:52
  • Ah yes you're correct, my change does one thing, and that is causing the `else` case in the loop to not execute when you have reached the end of the file. So the fix for you is to check for `EOF` together with `!isalnum`. – Some programmer dude Feb 21 '15 at 19:00
  • 1
    I added Weather Vane's code, well the last part of it - checking it after the while loop and it also helped. Thanks for suggestions – user3294564 Feb 21 '15 at 19:08

1 Answers1

1

The reason your "123" is skipped is because the count poc is left dangling after the last file read. There are two ways you can cure this.

1) Add a newline to the end of the last line in the file. The reason you originally did not skip the "123" is because you were treating the EOF value as a character. Better would be -

2) Check for a dangling poc value by repeating the tests on it, after the loop has terminated.

The code (with corrections suggested in above comments) would look like this.

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

int main(void) {

    FILE *li, *sa;
    int c, poc=0;
    char a[] = "___";               // removed length spec
    char b[] = "_____";             // removed length spec

    li = fopen("test.txt", "r");
    sa = fopen("sablona.txt", "w");

    while((c = getc(li)) != EOF) {  // altered end-of-file check

        if(isalnum(c))
            poc++;

        else if(poc>0 && poc<4){
            fputs(a, sa);
            poc = 0;
        } else if(poc>=4){
            fputs(b, sa); 
            poc = 0;
        }
        if(!isalnum(c))
            putc(c, sa);
    }

    if(poc>0 && poc<4){             // check for dangling poc
        fputs(a, sa);
        poc = 0;
    } else if(poc>=4){
        fputs(b, sa); 
        poc = 0;
    }

    fclose(li);
    fclose(sa);
    return 0;
}
Weather Vane
  • 33,872
  • 7
  • 36
  • 56
  • I am getting segmentation fault on this one. And can you explain me why there is no need for declaring size of a and b ? – user3294564 Feb 21 '15 at 18:57
  • 1
    If you don't specify the array length and at the same time initialise it with a value, the compiler will assign enough length, including the 0 terminator. But as your length did not allow room for the terminator, it was skipped, giving an unterminated character array rather than a string. I just copy/pasted this answer back and checked it - it runs ok with me. – Weather Vane Feb 21 '15 at 19:15