I compiled this (gcc compiler) :
#include< stdio.h>
main() {
unsigned char ch;
FILE *fp;
fp=fopen("trial","r");
while((ch=getc(fp))!=EOF)
printf("%c",ch);
fclose(fp);
}
It gives the follwing:
Warning: comparison is always true due to limited range of the data type
On executing, an endless stream of characters is printed on terminal.
(Assuming I created a file named "trial" before compiling the program and wrote some text in the file.)
Kindly explain the warning.....
Because EOF is -1 and your ch is unsigned char which means ch will never become -1.
Instead use int ch;
The EOF value in C is an int while ch here is a char. The char type is smaller than int and hence can represent less values than int can. EOF is one of the values which char simply can't ever represent and hence ch will never be equal to EOF.
In this scenario getc actually returns an int so it can represent EOF. But you are immediately shrinking it to a char and losing that extra information.
Here's a way to properly write this.
int cur;
FILE *fp;
fp=fopen("trial","r");
while((cur = getc(fp))!=EOF) {
unsigned char ch = cur;
printf("%c",ch);
}
fclose(fp);
getc() returns an int. You're truncating (and changing the signedness) it to unsigned char with that assignment, so it will never match EOF. Just change the type of ch to int and you'll be fine.
getc returns an integer for good reason. The EOF indicator is outside the range of a normal char, because otherwise you could confuse a legitimate character with the EOF indicator. However, you're assigning the results to a character which confines the answer to fall within the limits of a char value. In short, you're never going to know when the end of the file has been reached this way. Make "ch" an int type or assign result from call to getc to an unsigned char type after you compare it with EOF.
Related
This question already has answers here:
Comparing unsigned char and EOF
(6 answers)
Closed 5 years ago.
I’m learning C using Xcode 8 and the compiler doesn’t run any code after a while- or for-loop executes. is this a bug? how can I fix it?
In the example provided below printf("code executed after while-loop"); never executes
#include <stdio.h>
int getTheLine(char string[]);
int getTheLine(char string[]) {
char character;
int index;
index = 0;
while ((character = getchar()) >= EOF) {
string[index] = character;
++index;
}
printf("code executed after while-loop");
return index;
}
int main(int argc, const char * argv[]) {
char string[100];
int length = getTheLine(string);
printf("length %d\n", length);
return 0;
}
getchar returns an int not a char, and comparison with EOF should be done with the != operator instead of the >= operator.
...
int character; // int instead of char
int index;
index = 0;
while ((character = getchar()) != EOF) { // != instead of >=
...
It's the >= EOF, which will let the condition be always true. The reason is that a "valid" result of getchar() will be a positive integer, and a "non-valid" result like end-of-file will be EOF, which is negative (cf. getchar()):
EOF ... integer constant expression of type int and negative value
Hence, any valid result from getchar will be >EOF, while the end-of-file-result will be ==EOF, such that >= EOF will always match.
Write != EOF instead.
Note further that you do not terminate your string by the string-terminating-character '\0', such that using string like a string (e.g. in a printf("%s",string)) will yield undefined behaviour (crash or something else probably unwanted).
So write at least:
while ((character = getchar()) != EOF) {
string[index] = character;
++index;
}
string[index]='\0';
Then there is still the issue that you may write out of bounds, e.g. if one enters more then 100 characters in your example. But checking this is now beyond the actual question, which was about the infinite loop.
The symbolic constant EOF is an integer constant, of type int. It's (usually) defined as a macro as -1.
The problem is that the value -1 as an (32-bit) int has the value 0xffffffff and as a (8-bit) char the same value would be 0xff. Those two values are not equal. Which in turn means that your loop condition will never be false, leading to an infinite loop.
The solution to this problem is that all standard functions that reads characters returns them as an int. Which means your variable character needs to be of that type too.
Important note: It's a compiler implementation detail if plain char is a signed or an unsigned type. If it is signed then a comparison to an int would lead to sign extension when the char value is promoted in the comparison. That means a signed char with the value 0xff would be extended to the int value 0xffffffff. That means if char is signed then the comparison would work.
This means that your compile have char as unsigned char. So the unsigned char value 0xff after promotion to int will be 0x000000ff.
As for why the value -1 becomes 0xffffffff is because of how negative numbers are usually represented on computers, with something called two's complement.
You also have another couple of flaws in your code.
The first is that since the loop is infinite you will go way out of bounds of the string array, leading to undefined behavior (and a possible crash sooner or later). The solution to this is to add a condition to make sure that index never reaches 100 (in the specific case of your array, should really be passed as an argument).
The second problem is that if you intend to use the string array as an actual string, you need to terminate it. Strings in C are actually called null terminated strings. That terminator is the character '\0' (equal to integer 0), and need to be put at the end of every string you want to pass to a standard function handling such strings. Having this terminator means that an array of 100 characters only can have 99 characters in it, to be able to fit the terminator. This have implications to the solution to the above problem. As for how to add the terminator, simply do string[index] = '\0'; after the loop (if index is within bounds of course).
why does the following code work fine:
#include<stdio.h>
int main()
{
FILE *fp=fopen("input.txt","r+");
char c;
while((c=getc(fp))!=EOF)
{
printf("%c",c);
}
fclose(fp);
return 0;
}
but this code gives an error 'segmentation fault, core dumped':
#include<stdio.h>
int main()
{
FILE *fp=fopen("input.txt","r+");
char c;
while((c=fscanf(fp,"%c",&c))!=EOF)
{
printf("%c",c);
}
fclose(fp);
return 0;
}
input.txt contains a space separated list of characters like: a b c d e f
This will not work the way you expect:
while((c=fscanf(fp,"%c",&c))!=EOF)
getc() returns the character read, which can be EOF, but fscanf() returns the number of input items assigned, or EOF if there was a failure before any conversion took place.
You can't assign this return value to c, because the return value is not the character read (which you then try to print later).
You should try this instead:
while(fscanf(fp,"%c",&c) == 1)
Or:
while(fscanf(fp,"%c",&c) != EOF)
Which is equivalent to saying "As long as there is a character to read..."
Also, in the first case (the code where you use getc()), c should be int - you can have an infinite loop if the target platform uses unsigned chars, because c will always be converted to a positive int (again, only in platforms with unsigned chars), and thus will never be equal to EOF. If you check the manpages for getc() and putc() (and other functions that deal with a character), you will see that they receive int, not char.
i am trying to read a file in c.
i have a .txt file and it has that content:
file_one.txt file_two.txt file_three.txt file_four.txt
when i try to read this file with fopen i get this output:
file_one.txt file_two.txt file_three.txt file_four.txt\377
what does \377 mean? Here's my code.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]){
FILE *filelist;
char ch;
filelist=fopen("file-path", "rt");
while (!feof(filelist)) {
ch = getc(filelist);
printf("%c",ch);
}
fclose(filelist);
return 0;
}
The getc() function returns a result of type int, not of type char. Your char ch; should be int ch;.
Why does it return an int? Because the value it returns is either the character it just read (as an unsigned char converted to int) or the special value EOF (typically -1) to indicate either an input error or an end-of-file condition.
Don't use the feof() function to detect the end of input. It returns true only after you've run out of input. Your last call to getc() is returning EOF, which when stored into a char object is converted to (char)-1, which is typically '\377'.
Another problem is that feof() will never return a true value if there was an input error; in that case, ferror() will return true. Use feof() and/or ferror() after getc() returns EOF, to tell why it returned EOF.
To read from a file until you reach the end of it:
int ch;
while ((ch = getc(filelist)) != EOF) {
/* ch contains the last character read; do what you like with it */
}
Suggested reading: Section 12 of the comp.lang.c FAQ.
The \377 is an octal escape sequence, decimal 255, all bits set. It comes from converting EOF - which usually has the value -1 - to a char, due to
while (!feof(filelist)) {
feof(filelist) only becoming true after you have tried to read past the file.
So at the end of the file, you enter the loop once more, and the getc() returns EOF.
I can't figure out why my while loop won't work. The code works fine without it... The purpose of the code is to find a secret message in a bin file. So I got the code to find the letters, but now when I try to get it to loop until the end of the file, it doesn't work. I'm new at this. What am I doing wrong?
main(){
FILE* message;
int i, start;
long int size;
char keep[1];
message = fopen("c:\\myFiles\\Message.dat", "rb");
if(message == NULL){
printf("There was a problem reading the file. \n");
exit(-1);
}
//the first 4 bytes contain an int that tells how many subsequent bytes you can throw away
fread(&start, sizeof(int), 1, message);
printf("%i \n", start); //#of first 4 bytes was 280
fseek(message, start, SEEK_CUR); //skip 280 bytes
keep[0] = fgetc(message); //get next character, keep it
printf("%c", keep[0]); //print character
while( (keep[0] = getc(message)) != EOF) {
fread(&start, sizeof(int), 1, message);
fseek(message, start, SEEK_CUR);
keep[0] = fgetc(message);
printf("%c", keep[0]);
}
fclose(message);
system("pause");
}
EDIT:
After looking at my code in the debugger, it looks like having "getc" in the while loop threw everything off. I fixed it by creating a new char called letter, and then replacing my code with this:
fread(&start, sizeof(int), 1, message);
fseek(message, start, SEEK_CUR);
while( (letter = getc(message)) != EOF) {
printf("%c", letter);
fread(&start, sizeof(int), 1, message);
fseek(message, start, SEEK_CUR);
}
It works like a charm now. Any more suggestions are certainly welcome. Thanks everyone.
The return value from getc() and its relatives is an int, not a char.
If you assign the result of getc() to a char, one of two things happens when it returns EOF:
If plain char is unsigned, then EOF is converted to 0xFF, and 0xFF != EOF, so the loop never terminates.
If plain char is signed, then EOF is equivalent to a valid character (in the 8859-1 code set, that's ÿ, y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS), and your loop may terminate early.
Given the problem you face, we can tentatively guess you have plain char as an unsigned type.
The reason that getc() et al return an int is that they have to return every possible value that can fit in a char and also a distinct value, EOF. In the C standard, it says:
ISO/IEC 9899:2011 §7.21.7.1 The fgetc() function
int fgetc(FILE *stream);
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 ...
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.
Similar wording applies to the getc() function and the getchar() function: they are defined to behave like the fgetc() function except that if getc() is implemented as a macro, it may take liberties with the file stream argument that are not normally granted to standard macros — specifically, the stream argument expression may be evaluated more than once, so calling getc() with side-effects (getc(fp++)) is very silly (but change to fgetc() and it would be safe, but still eccentric).
In your loop, you could use:
int c;
while ((c = getc(message)) != EOF) {
keep[0] = c;
This preserves the assignment to keep[0]; I'm not sure you truly need it.
You should be checking the other calls to fgets(), getc(), fread() to make sure you are getting what you expect as input. Especially on input, you cannot really afford to skip those checks. Sooner, rather than later, something will go wrong and if you aren't religiously checking the return statuses, your code is likely to crash, or simply 'go wrong'.
There are 256 different char values that might be returned by getc() and stored in a char variable like keep[0] (yes, I'm oversummarising wildly). To detect end-of-file reliably, EOF has to have a value different from all of them. That's why getc() returns int rather than char: because a 257th distinct value for EOF wouldn't fit into a char.
Thus you need to store the value returned by getc() in an int at least until you check it against EOF:
int tmpc;
while( (tmpc = getc(message)) != EOF) {
keep[0] = tmpc;
...
I'm attempting to use the getc() function to copy the contents of one file into another. But I'm making an unknown logical error because the output of the following program is a bunch of garbage.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *f;
FILE *write;
f = fopen("nums.csv","r");
write = fopen("numsWrite.dat","w");
char tempChar;
int i;
for(i = 0; (tempChar = getc(f)) != EOF; i++)
{
tempChar = getc(f);
fprintf(write,"%c",tempChar);
}
fprintf(write,"\n");
fclose(f);
fclose(write);
return 0;
}
content of nums.csv is:
1256,2548,35151,15,56,38
program returns:
2624,55,55,8
There are several problems with your code.
int main() should be int main(void); this is a minor issue that almost certainly won't hurt anything, but the latter is more correct.
You don't check whether the fopen() calls succeed.
You're using i to count the characters you read, but you never do anything with its value.
The getc() function returns a result of type int, so you should definitely make tempChar an int. The reason for this is that it can return either a valid character value (which will fit in a char object) or the value EOF which is typically -1. By storing the result of getc() in a char object, either you'll never see EOF (if plain char is unsigned), or you won't be able to distinguish EOF from a valid input character.
In a comment on Razvan's answer, you said you changed the test to tempChar != EOF. Apart from the problem I explained above, on the first iteration of the loop tempChar has not been initialized, and the result of the comparison is unpredictable.
The conventional way to write an input loop using getc() is:
int c;
while ((c = getc(f)) != EOF) {
/* do something with c */
}
As a matter of style, write is not a very good name for a FILE*. For one thing, there's a function of that name (defined by POSIX, not by C, but it's still potentially confusing). You might call the FILE* objects in and out instead.
You call getc two times: once in the for condition and once in the for body. Delete this line: tempChar = getc(f); and try again.