int main()
{
FILE *ft;
char ch;
ft=fopen("abc.txt","r+");
if(ft==NULL)
{
printf("can not open target file\n");
exit(1);
}
while(1)
{
ch=fgetc(ft);
if(ch==EOF)
{
printf("done");
break;
}
if(ch=='i')
{
fputc('a',ft);
}
}
fclose(ft);
return 0;
}
As one can see that I want to edit abc.txt in such a way that i is replaced by a in it.
The program works fine but when I open abc.txt externally, it seemed to be unedited.
Any possible reason for that?
Why in this case the character after i is not replace by a, as the answers suggest?
Analysis
There are multiple problems:
fgetc() returns an int, not a char; it has to return every valid char value plus a separate value, EOF. As written, you can't reliably detect EOF. If char is an unsigned type, you'll never find EOF; if char is a signed type, you'll misidentify some valid character (often ÿ, y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS) as EOF.
If you switch between input and output on a file opened for update mode, you must use a file positioning operation (fseek(), rewind(), nominally fsetpos()) between reading and writing; and you must use a positioning operation or fflush() between writing and reading.
It is a good idea to close what you open (now fixed in the code).
If your writes worked, you'd overwrite the character after the i with a.
Synthesis
These changes lead to:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *ft;
char const *name = "abc.txt";
int ch;
ft = fopen(name, "r+");
if (ft == NULL)
{
fprintf(stderr, "cannot open target file %s\n", name);
exit(1);
}
while ((ch = fgetc(ft)) != EOF)
{
if (ch == 'i')
{
fseek(ft, -1, SEEK_CUR);
fputc('a',ft);
fseek(ft, 0, SEEK_CUR);
}
}
fclose(ft);
return 0;
}
There is room for more error checking.
Exegesis
Input followed by output requires seeks
The fseek(ft, 0, SEEK_CUR); statement is required by the C standard.
ISO/IEC 9899:2011 §7.21.5.3 The fopen function
¶7 When a file is opened with update mode ('+' as the second or third character in the
above list of mode argument values), both input and output may be performed on the
associated stream. However, output shall not be directly followed by input without an
intervening call to the fflush function or to a file positioning function (fseek,
fsetpos, or rewind), and input shall not be directly followed by output without an
intervening call to a file positioning function, unless the input operation encounters end-of-
file. Opening (or creating) a text file with update mode may instead open (or create) a
binary stream in some implementations.
(Emphasis added.)
fgetc() returns an int
Quotes from ISO/IEC 9899:2011, the current C standard.
§7.21 Input/output <stdio.h>
§7.21.1 Introduction
EOF which expands to an integer constant expression, with type int and a negative value, that
is returned by several functions to indicate end-of-file, that is, no more input from a
stream;
§7.21.7.1 The fgetc function
int fgetc(FILE *stream);
¶2 If the end-of-file indicator for the input stream pointed to by stream is not set and a
next character is present, the fgetc function obtains that character as an unsigned char converted to an int and advances the associated file position indicator for the
stream (if defined).
Returns
¶3 If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-file indicator for the stream is set and the fgetc function returns EOF. Otherwise, the
fgetc function returns the next character from the input stream pointed to by stream.
If a read error occurs, the error indicator for the stream is set and the fgetc function
returns EOF.289)
289) An end-of-file and a read error can be distinguished by use of the feof and ferror functions.
So, EOF is a negative integer (conventionally it is -1, but the standard does not require that). The fgetc() function either returns EOF or the value of the character as an unsigned char (in the range 0..UCHAR_MAX, usually 0..255).
§6.2.5 Types
¶3 An object declared as type char is large enough to store any member of the basic
execution character set. If a member of the basic execution character set is stored in a
char object, its value is guaranteed to be nonnegative. If any other character is stored in
a char object, the resulting value is implementation-defined but shall be within the range
of values that can be represented in that type.
¶5 An object declared as type signed char occupies the same amount of storage as a
‘‘plain’’ char object.
§6 For each of the signed integer types, there is a corresponding (but different) unsigned
integer type (designated with the keyword unsigned) that uses the same amount of
storage (including sign information) and has the same alignment requirements.
§15 The three types char, signed char, and unsigned char are collectively called
the character types. The implementation shall define char to have the same range,
representation, and behavior as either signed char or unsigned char.45)
45) CHAR_MIN, defined in <limits.h>, will have one of the values 0 or SCHAR_MIN, and this can be
used to distinguish the two options. Irrespective of the choice made, char is a separate type from the
other two and is not compatible with either.
This justifies my assertion that plain char can be a signed or an unsigned type.
Now consider:
char c = fgetc(fp);
if (c == EOF)
…
Suppose fgetc() returns EOF, and plain char is an unsigned (8-bit) type, and EOF is -1. The assignment puts the value 0xFF into c, which is a positive integer. When the comparison is made, c is promoted to an int (and hence to the value 255), and 255 is not negative, so the comparison fails.
Conversely, suppose that plain char is a signed (8-bit) type and the character set is ISO 8859-15. If fgetc() returns ÿ, the value assigned will be the bit pattern 0b11111111, which is the same as -1, so in the comparison, c will be converted to -1 and the comparison c == EOF will return true even though a valid character was read.
You can tweak the details, but the basic argument remains valid while sizeof(char) < sizeof(int). There are DSP chips where that doesn't apply; you have to rethink the rules. Even so, the basic point remains; fgetc() returns an int, not a char.
If your data is truly ASCII (7-bit data), then all characters are in the range 0..127 and you won't run into the misinterpretation of ÿ problem. However, if your char type is unsigned, you still have the 'cannot detect EOF' problem, so your program will run for a long time. If you need to consider portability, you will take this into account. These are the professional grade issues that you need to handle as a C programmer. You can kludge your way to programs that work on your system for your data relatively easily and without taking all these nuances into account. But your program won't work on other people's systems.
You are not changing the 'i' in abc.txt, you are changing the next character after 'i'. Try to put fseek(ft, -1, SEEK_CUR); before your fputc('a', ft);.
After you read a 'i' character, the file position indicator of ft will be the character after this 'i', and when you write a character by fputc(), this character will be write at the current file position, i.e. the character after 'i'. See fseek(3) for further details.
After reading 'i' you need to "step back" to write to the correct location.
if(ch=='i')
{
fseek(ft, -1, SEEK_CUR);
fputc('a',ft);
}
Related
I have written a code
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
fp=fopen("lets.txt","r+");
if(fp==NULL)
{
printf("ERROR");
exit(1);
}
else
{
char ch,ch1;
while(!feof(fp))
{
ch= fgetc(fp);
printf("%c",ch);
}
printf("\n\nYou want to write something? (1/0)");
int n;
scanf("%d",&n);
if(n==1)
{
fputs("Jenny",fp);
ch1 = fgetc(fp);
printf("%c\n", ch1);
while(ch1 != EOF)
{
ch1=fgetc(fp);
printf("%c",ch1);
}
fclose(fp);
}
else{
printf("File Closed ");
fclose(fp);
}
}
}
I have tried to insert a string inside an already existing file "lets.txt"
but when I run this code, this is shown in the Terminal
I was expecting this to just put Jenny into the final file but it's also adding other text which was present before it and lots of NULL.
Is this because of something like temporary memory storage or something like that or just some mistake in the code?
First of all, the lines
char ch,ch1;
while(!feof(fp))
{
ch= fgetc(fp);
printf("%c",ch);
}
are wrong.
If you want ch to be guaranteed to be able to represent the value EOF and also want to be able to distinguish it from every possible character code, then you must store the return value of fgetc in an int, not a char. Please note that fgetc returns an int, not a char. See this other answer for more information on this issue.
Also, the function feof will only return a non-zero value (i.e. true) if a previous read operation has already failed due to end-of-file. It does not provide any indication of whether the next read operation will fail. This means that if fgetc returns EOF, you will print that value as if fgetc were successful, which is wrong. See the following question for further information on this issue:
Why is “while( !feof(file) )” always wrong?
For the reasons stated above, I suggest that you change these lines to the following:
int ch, ch1;
while ( ( ch = fgetc(fp) ) != EOF )
{
printf( "%c", ch );
}
Another issue is that when a file is opened in update mode (i.e. it is opened with a + in the mode string, for example "r+" as you are doing), you cannot freely change between reading and writing. According to §7.21.5.3 ¶7 of the ISO C11 standard,
output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and
input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.
If you break any of these rules, than your program will be invoking undefined behavior, which means that anything can happen, which includes the possibility that you get invalid output.
For this reason, I suggest that you change the lines
fputs("Jenny",fp);
ch1 = fgetc(fp);
to:
fseek( fp, 0, SEEK_CUR );
fputs("Jenny",fp);
fflush( fp );
ch1 = fgetc(fp);
In contrast to the line fflush( fp );, which is absolutely necessary, the line fseek( fp, 0, SEEK_CUR ); actually isn't necessary according to the rules stated above, because you encountered end-of-file. But it probably is a good idea to keep that line anyway, for example in case you later change your program to stop reading for some other reason besides end-of-file. In that case, that line would be required.
Re: "I changed the condition for the while loop to this simple form-
ch = fgetc(fp); while(ch != EOF) But it is still showing the same
result.
The value returned by getchar() must be stored in an int:
ch= fgetc(fp);
ch has been declared as a char. Storing the value in a char makes testing for EOF unreliable. C17 states that EOF has a negative int value. On some implementations, char is unsigned, hence it can't represent negative values.
On implementations where the type char is signed, assuming EOF is defined as -1 (which is the case on most implementations), it's impossible to distinguish EOF from the character code 255 (which would be stored as the value -1 in a char, but as 255 in an int).
From the man page:
fgetc(), getc(), and getchar() return the character read as an
unsigned char cast to an int or EOF on end of file or error.
It further states:
If the integer value returned by getchar() is stored into a
variable of type char and then compared against the integer
constant EOF, the comparison may never succeed, because sign-
extension of a variable of type char on widening to integer is
implementation-defined.
which is relevant to fgetc as well.
Possible fix:
Declare ch as an int.
You haven't set the file pointer when switching between read and write. The MSVC man page says about fopen
However, when you switch from reading to writing, the input operation must encounter an EOF marker. If there's no EOF, you must use an intervening call to a file positioning function. The file positioning functions are fsetpos, fseek, and rewind. When you switch from writing to reading, you must use an intervening call to either fflush or to a file positioning function.
I'm learning the C programming on a raspberry pi, however I found that my program never catches the EOF successfully. I use char c=0; printf("%d",c-1); to test the char type, finding that the char type ranges from 0 to 255, as an unsigned short. but the EOF defined in stdio.h is (-1). So is the wrong cc package installed on my Pi? how can I fix it? If I changed the EOF value in stdio.h manually, will there be further problems?
what worries me is that ,when I learning from the K&R book, there are examples which use code like while ((c=getchar())!=EOF), I followed that on my Ubuntu machine and it works fine. I just wonder if such kind of syntax is abandoned by modern C practice or there is something conflict in my Raspberry Pi?
here is my code:
#include <stdio.h>
int main( void )
{
char c;
int i=0;
while ((c=getchar())!=EOF&&i<50) {
putchar(c);
i++;
}
if (c==EOF)
printf("\nEOF got.\n");
while ((c=getchar())!=EOF&&i<500) {
printf("%d",c);
i++;
}
}
even when I redirect the input to an file, it keeps printing 255 on the screen, never terminate this program.
Finally I found that I'm wrong,In the K&R book, it defined c as an int, not a char. Problem solved.
You need to store the character read by fgetc(), getchar(), etc. in an int so you can catch the EOF. This is well-known and has always been the case everywhere. EOF must be distinguishable from all proper characters, so it was decided that functions like fgetc() return valid characters as non-negative values (even if char is signed). An end-of-file condition is signalled by -1, which is negative and thus cannot collide with any valid character fgetc() could return.
Do not edit the system headers and especially do not change the value of constants defined there. If you do that, you break these headers. Notice that even if you change the value of EOF in the headers, this won't change the value functions like fgetc() return on end-of-file or error, it just makes EOF have the wrong value.
Why is EOF defined to be −1 when −1 cannot be represented in a char?
Because EOF isn't a character but a state.
If I changed the EOF value in stdio.h manually, will there be further
problems?
Absolutely, since you would be effectively breaking the header entirely. A header is not an actual function, just a set of prototypes and declarations for functions that are defined elsewhere ABSOLUTELY DO NOT change system headers, you will never succeed in doing anything but breaking your code, project and/or worse things.
On the subject of EOF: EOF is not a character, and thus cannot be represented in a character variable. To get around this, most programmers simple use an int value (by default signed) that can interpret the -1 from EOF. The reason that EOF can never be a character is because otherwise there would be one character indistinguishable from the end of file indicator.
int versus char.
fgetc() returns an int, not char. The values returned are in the range of unsigned char and EOF. This is typically 257 different values. So saving the result in char, signed char, unsigned char will lose some distinguishably.
Instead save the fgetc() return value in an int. After testing for an EOF result, the value can be saved as a char if needed.
// char c;
int c;
...
while ((c=getchar())!=EOF&&i<50) {
char ch = c;
...
Detail: "Why is EOF defined to be −1 when −1 cannot be represented in a char?" misleads. On systems where char is signed and EOF == -1, a char can have the value of EOF. Yet on such systems, a char can have a value of -1 that represents a character too - they overlap. So a char cannot distinctively represent all char and EOF. Best to use an int to save the return value of fgetc().
... the fgetc function obtains that character as an unsigned char converted to an int and ...
If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, ... and the fgetc function returns EOF. ... C11 §7.21.7.1 2-3
I have the following code:
FILE *f = fopen('/path/to/some/file', 'rb');
char c;
while((c = fgetc(f)) != EOF)
{
printf("next char: '%c', '%d'", c, c);
}
For some reason, when printing out the characters, at the end of the file, an un-renderable character gets printed out, along with the ASCII ordinal -1.
next char: '?', '-1'
What character is this supposed to be? I know it's not EOF because there's a check for that, and quickly after the character is printed, the program SEGFAULT.
The trouble is that fgetc() and its relatives return an int, not a char:
If the end-of-file indicator for the input stream pointed to by stream is not set and a
next character is present, the fgetc function obtains that character as an unsigned char converted to an int and advances the associated file position indicator for the
stream (if defined).
If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-
file indicator for the stream is set and the fgetc function returns EOF.
It has to return every possible valid character value and a distinct value, EOF (which is negative, and usually but not necessarily -1).
When you read the value into a char instead of an int, one of two undesirable things happens:
If plain char is unsigned, then you never get a value equal to EOF, so the loop never terminates.
If plain char is signed, then you can mistake a legitimate character, 0xFF (often ÿ, y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS) is treated the same as EOF, so you detect EOF prematurely.
Either way, it is not good.
The Fix
The fix is to use int c; instead of char c;.
Incidentally, the fopen() call should not compile:
FILE *f = fopen('/path/to/some/file', 'rb');
should be:
FILE *f = fopen("/path/to/some/file", "rb");
Always check the result of fopen(); of all the I/O functions, it is more prone to failure than almost any other (not through its own fault, but because the user or programmer makes a mistake with the file name).
This is the culprit:
char c;
Please change it to:
int c;
The return type of fgetc is int, not char. You get strange behavior when you convert int to char in some platforms.
int main()
{
FILE *ft;
char ch;
ft=fopen("abc.txt","r+");
if(ft==NULL)
{
printf("can not open target file\n");
exit(1);
}
while(1)
{
ch=fgetc(ft);
if(ch==EOF)
{
printf("done");
break;
}
if(ch=='i')
{
fputc('a',ft);
}
}
fclose(ft);
return 0;
}
As one can see that I want to edit abc.txt in such a way that i is replaced by a in it.
The program works fine but when I open abc.txt externally, it seemed to be unedited.
Any possible reason for that?
Why in this case the character after i is not replace by a, as the answers suggest?
Analysis
There are multiple problems:
fgetc() returns an int, not a char; it has to return every valid char value plus a separate value, EOF. As written, you can't reliably detect EOF. If char is an unsigned type, you'll never find EOF; if char is a signed type, you'll misidentify some valid character (often ÿ, y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS) as EOF.
If you switch between input and output on a file opened for update mode, you must use a file positioning operation (fseek(), rewind(), nominally fsetpos()) between reading and writing; and you must use a positioning operation or fflush() between writing and reading.
It is a good idea to close what you open (now fixed in the code).
If your writes worked, you'd overwrite the character after the i with a.
Synthesis
These changes lead to:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *ft;
char const *name = "abc.txt";
int ch;
ft = fopen(name, "r+");
if (ft == NULL)
{
fprintf(stderr, "cannot open target file %s\n", name);
exit(1);
}
while ((ch = fgetc(ft)) != EOF)
{
if (ch == 'i')
{
fseek(ft, -1, SEEK_CUR);
fputc('a',ft);
fseek(ft, 0, SEEK_CUR);
}
}
fclose(ft);
return 0;
}
There is room for more error checking.
Exegesis
Input followed by output requires seeks
The fseek(ft, 0, SEEK_CUR); statement is required by the C standard.
ISO/IEC 9899:2011 §7.21.5.3 The fopen function
¶7 When a file is opened with update mode ('+' as the second or third character in the
above list of mode argument values), both input and output may be performed on the
associated stream. However, output shall not be directly followed by input without an
intervening call to the fflush function or to a file positioning function (fseek,
fsetpos, or rewind), and input shall not be directly followed by output without an
intervening call to a file positioning function, unless the input operation encounters end-of-
file. Opening (or creating) a text file with update mode may instead open (or create) a
binary stream in some implementations.
(Emphasis added.)
fgetc() returns an int
Quotes from ISO/IEC 9899:2011, the current C standard.
§7.21 Input/output <stdio.h>
§7.21.1 Introduction
EOF which expands to an integer constant expression, with type int and a negative value, that
is returned by several functions to indicate end-of-file, that is, no more input from a
stream;
§7.21.7.1 The fgetc function
int fgetc(FILE *stream);
¶2 If the end-of-file indicator for the input stream pointed to by stream is not set and a
next character is present, the fgetc function obtains that character as an unsigned char converted to an int and advances the associated file position indicator for the
stream (if defined).
Returns
¶3 If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-file indicator for the stream is set and the fgetc function returns EOF. Otherwise, the
fgetc function returns the next character from the input stream pointed to by stream.
If a read error occurs, the error indicator for the stream is set and the fgetc function
returns EOF.289)
289) An end-of-file and a read error can be distinguished by use of the feof and ferror functions.
So, EOF is a negative integer (conventionally it is -1, but the standard does not require that). The fgetc() function either returns EOF or the value of the character as an unsigned char (in the range 0..UCHAR_MAX, usually 0..255).
§6.2.5 Types
¶3 An object declared as type char is large enough to store any member of the basic
execution character set. If a member of the basic execution character set is stored in a
char object, its value is guaranteed to be nonnegative. If any other character is stored in
a char object, the resulting value is implementation-defined but shall be within the range
of values that can be represented in that type.
¶5 An object declared as type signed char occupies the same amount of storage as a
‘‘plain’’ char object.
§6 For each of the signed integer types, there is a corresponding (but different) unsigned
integer type (designated with the keyword unsigned) that uses the same amount of
storage (including sign information) and has the same alignment requirements.
§15 The three types char, signed char, and unsigned char are collectively called
the character types. The implementation shall define char to have the same range,
representation, and behavior as either signed char or unsigned char.45)
45) CHAR_MIN, defined in <limits.h>, will have one of the values 0 or SCHAR_MIN, and this can be
used to distinguish the two options. Irrespective of the choice made, char is a separate type from the
other two and is not compatible with either.
This justifies my assertion that plain char can be a signed or an unsigned type.
Now consider:
char c = fgetc(fp);
if (c == EOF)
…
Suppose fgetc() returns EOF, and plain char is an unsigned (8-bit) type, and EOF is -1. The assignment puts the value 0xFF into c, which is a positive integer. When the comparison is made, c is promoted to an int (and hence to the value 255), and 255 is not negative, so the comparison fails.
Conversely, suppose that plain char is a signed (8-bit) type and the character set is ISO 8859-15. If fgetc() returns ÿ, the value assigned will be the bit pattern 0b11111111, which is the same as -1, so in the comparison, c will be converted to -1 and the comparison c == EOF will return true even though a valid character was read.
You can tweak the details, but the basic argument remains valid while sizeof(char) < sizeof(int). There are DSP chips where that doesn't apply; you have to rethink the rules. Even so, the basic point remains; fgetc() returns an int, not a char.
If your data is truly ASCII (7-bit data), then all characters are in the range 0..127 and you won't run into the misinterpretation of ÿ problem. However, if your char type is unsigned, you still have the 'cannot detect EOF' problem, so your program will run for a long time. If you need to consider portability, you will take this into account. These are the professional grade issues that you need to handle as a C programmer. You can kludge your way to programs that work on your system for your data relatively easily and without taking all these nuances into account. But your program won't work on other people's systems.
You are not changing the 'i' in abc.txt, you are changing the next character after 'i'. Try to put fseek(ft, -1, SEEK_CUR); before your fputc('a', ft);.
After you read a 'i' character, the file position indicator of ft will be the character after this 'i', and when you write a character by fputc(), this character will be write at the current file position, i.e. the character after 'i'. See fseek(3) for further details.
After reading 'i' you need to "step back" to write to the correct location.
if(ch=='i')
{
fseek(ft, -1, SEEK_CUR);
fputc('a',ft);
}
Is EOF always negative?
I'm thinking of writing a function that reads the next word in the input and returns the line number the word was found in or EOF if the end of the input has been reached. If EOF is not necessarily negative, the function would be incorrect.
EOF is always == EOF. Don't assume anything else.
On a second reading of the standard (and as per some other comments here) it seems EOF is always negative - and for the use specified in this question (line number or EOF) it would work. What I meant to warn against (and still do) is assuming characters are positive and EOF is negative.
Remember that it's possible for a standard conforming C implementation to have negative character values - this is even mentioned in 'The C programming language' (K&R). Printing characters are always positive, but on some architectures (probably all ancient), control characters are negative. The C standard does not specify whether the char type is signed or unsigned, and the only character constant guaranteed to have the same value across platforms, is '\0'.
Yes, EOF is always negative.
The Standard says:
7.19 Input/output
7.19.1 Introduction
3 The macros are [...] EOF which
expands to an integer constant
expression, with type int and a
negative value, that is returned by
several functions to indicate
end-of-file, that is, no more input
from a stream;
Note that there's no problem with "plain" char being signed. The <stdio.h> functions which deal with chars, specifically cast the characters to unsigned char and then to int, so that all valid characters have a positive value. For example:
int fgetc(FILE *stream)
7.19.7.1
... the fgetc function obtains that character as an unsigned char converted to an int ...
Have that function return
the line number the word was found in
or -1 in case the end of the input has been reached
Problem solved, without a need for relying on any EOF values. The caller can easily test for greater-or-equal-to-zero for a successful call, and assume EOF/IO-error otherwise.
From the online draft n1256, 17.9.1.3:
EOF
which expands to an integer constant expression, with type int and a negative value,
that is returned by several functions to indicate end-of-file, that is, no more input
from a stream;
EOF is always negative, though it may not always be -1.
For issues like this, I prefer separating error conditions from data by returning an error code (SUCCESS, END_OF_FILE, READ_ERROR, etc.) as the function's return value, and then writing the data of interest to separate parameters, such as
int getNextWord (FILE *stream, char *buffer, size_t bufferSize, int *lineNumber)
{
if (!fgets(buffer, bufferSize, stream))
{
if (feof(stream)) return END_OF_FILE; else return READ_ERROR;
}
else
{
// figure out the line number
*lineNumber = ...;
}
return SUCCESS;
}
EOF is a condition, rather than a value. The exact value of this sentinel is implementation defined. In a lot of cases, it is a negative number.
From wikipedia :
The actual value of EOF is a
system-dependent negative number,
commonly -1, which is guaranteed to be
unequal to any valid character code.
But no references ...
From Secure Coding : Detect and handle input and output errors
EOF is negative but only when sizeof(int) > sizeof(char).