I got a big problem using fgetc() and i can't figure it out... I try to parse a text file, everything compile but at the execution I got an infinite loop or a segfault (Code::blocks), my text file is like that: {"USD_EUR": "0.8631364", "EUR_USD": "1.3964719"} with 16 rates change. I try to put all my float in rate[16]...
FILE* file = NULL;
file = fopen(myFile, "r+");
int value,i;
float rate[16];
char* str = "";
if (file != NULL)
{
do
{
value = fgetc(file);
printf("%c \n",value);
while(value > 48 && value < 57)
{
value = fgetc(file);
strcat(str, value);
//printf("%s \n", str);
}
rate[i] = atof(str);
i++;
str = "";
}while(value != 125); // 125 = }
while(value =! EOF); should be while(value != EOF);
It's a big difference. First case is an assignment to the variable value, second case looks if value is not equal to EOF.
EOF is a macro and usually have the value -1, that means that !EOF becomes 0. Since you have a do{} while() it will run once but not more since condition is false.
while(value =! EOF) is not same as while(value != EOF)
What you need is the latter while(value != EOF)
in the while loop you are assigning the value to the variable value.
`while(value =! EOF);`
The value of EOF is -1.(i.e) End of file. if it is !-1, then it will take as 0.
As it is a do while only once the loop will be executed, next time the condition will be false. So it gets only one character.
You can use
`while(value != EOF);`
which means not equal to EOF. Then the condition will be true and the loop will be executed till the condition becomes false.
Declaration of value is incorrect and make that correct.
int value;
While ( value != EOF ) is comparing the value to EOF. Here EOF is a macro having the
value as -1. Comparing the value with that. You can see that using cc -E while compiling.
(value =!EOF) means that value =! (-1) So !(-1) comes zero. That will assign to the variable value. So in condition zero is false. So it come out from the loop. And you can check the value of variable value by printing that variable.
The following code does the job of reading/echoing a input file
char by char.
#include <stdio.h>
#include <stdlib.h>
char *theFile = "input.txt";
int main()
{
FILE* file = NULL;
int value;
if( NULL == ( file = fopen(theFile, "r") ) )
{ // then fopen failed
perror( "fopen failed" );
exit(EXIT_FAILURE );
}
// implied else, fopen successful
while( EOF != (value = fgetc(file) ) )
{
printf("%c \n",value);
} // end while
return(0);
} // end function: main
Related
I have implemented my own fgets (i.e myfgets). When there is NULL string in my file which has to be read by myfgets function then it print all the string (good) but with some garbage(bad), but if I use predefine fgets then there is no garbage. Below is my code and file content which has NULL string in it.
myfile
hello word NULL Good Morning // if NULL is removed then its good
#include<stdio.h>
#include<stdlib.h>
char *myfgets(char *Buffer_address,int size,FILE *fp)
{
register int c;
register char *I_help_Notify_IfNotRead;
I_help_Notify_IfNotRead = Buffer_address;
while(--size>0 && (c=getc(fp))!=EOF )
{
if((*I_help_Notify_IfNotRead++=c)=='\n')
break;
*I_help_Notify_IfNotRead='\0';
}
return ( c==EOF && I_help_Notify_IfNotRead == Buffer_address ) ? NULL : Buffer_address;
}
int main()
{
char ch[100];
FILE *fp ;
fp=fopen("myfile","r");
char * pp=(myfgets(ch,100,fp));
printf("%s",pp);
exit(EXIT_SUCCESS); // No need to close(fp) because exit does for us
}
OUTPUT:
hello word NULL Good Morning (good)
E����[�s^� (garbage) // Why am I getting this but not with predefine fgets?
Your logic to null-terminate the string is broken. You write a NUL byte after every character except the last one. Move the line which writes the NUL to just after the loop.
By the way, I have seen worse variable names than I_help_Notify_IfNotRead but not often. What was wrong with out?
The null character is not appended at the correct point #rici & #Jim Balter. That is the main issue. Suggest
if (size > 0) {
while(--size>0 && (c=getc(fp)) != EOF) {
*I_help_Notify_IfNotRead++ = c;
if (c == '\n') break;
}
*I_help_Notify_IfNotRead = '\0';
}
Corner case problems:
If size == 1, the null character is not written. (fixed above)
myfgets() does not fulfill: "If a read error occurs during the operation, ... a null pointer is returned." Maybe:
if (c == EOF) {
if (ferror(fp)) return NULL;
if (feof(fp) && I_help_Notify_IfNotRead == Buffer_address) return NULL;
}
return Buffer_address;
Write a program that reads input up to # and reports the number of times that the sequence ei occurs
I have this question and I found a code here for this but I'm unable to figure out what the int c1 part does. Here's the code :
#include <stdio.h>
int main(void) {
int c;
int ei_count = 0;
while ((c = getchar())!= '#') {
if (c == 'e') {
int c1 = getchar();
if (c1 == 'i')
ei_count++;
}
}
printf("ei appeared %d times\n", ei_count);
return(0);
}
My question is, how does the if condition work? Can someone please explain ?
I'm new at C
The c1-part is a broken try at scanning the second part of ei, they could have reused c without introducing more errors.
Better alternative:
#include <stdio.h>
int main(void) {
int c, last = 0, ei_count = 0;
while ((c = getchar()) >= 0 && c != '#') {
ei_count += last && c == 'i';
last = c == 'e';
}
printf("ei appeared %d times\n", ei_count);
}
Corrected errors:
neither ei nor # recognized after e.
infinite loop on EOF / input error.
Random facts:
main has an implicit return 0; just before the closing brace.
getchar() returns an int, so it can return -1 on failure and an unsigned char converted to int on success. Always check for failure.
logical and comparison operators always return 0 or 1.
0 is logical false, all else is logical true.
return is not a function call: Use return 0; without parentheses.
That part you mentioned is a way to find a pattern like "ei". At the first moment the code try to find the 'e' character in a loop, and then, once it is found, the code checks if the next char is the letter 'i'. Case not, start again the loop to find another 'e' char.
This is not an good approach since there is no error verification during the getchar() operation and you can fall on a infinite loop.
Oversimplified, it's just a state machine.
Stepping through line-by-line:
while ((c = getchar())!= '#') {
Read input and assign it to the variable c. If that read in char is anything but #, execute the body of the while, otherwise jump over it.
if (c == 'e') {
If the read in character is an e, then we want to execute the internal block. If it's not, skip to the end of this block.
int c1 = getchar();
Read another character.
if (c1 == 'i') ei_count++;
If the new character is an i, then increment the counter of found items.
} close if (if e was found)
} close while.
It's worth pointing out there is a very clear flaw in the logic flow, however. Think about what happens if you have the input "eei".
In C, char and int data types are pretty much the same thing. In an assignment statement, the final result of the calculations are converted to the type of the variable being assigned to. Probably in this example, the author of this code assumed that the value returned by getchar() function which is of type int cannot be assigned to a char variable. You can use a char type for the c1 variable, since the getchar() function returns the ASCII code of the next character in the input, and the value is automatically converted to char during assingment. In the next if statement, you can easily compare the value of c1 with the character value i.
This code is a little bit buggy, for if you enter e# as an input, the program hangs. The reason is that c1 = getchar(); statement in the if block assigns '#' value to variable c1, and the comparison obviously fails, and at the next iteration of the while loop, getchar() returns a value after the '#' character in the input stream, which is a garbage value unless you entered more other characters after the '#' character.
Here's my code with a few fixes:
#include <stdio.h>
int main(void) {
char ch, next;
int ei_cnt = 0;
while((ch = getchar()) != '#') {
if(ch == 'e') {
next = getchar();
if(next == '#')
break;
if(next == 'i')
ei_cnt++;
}
}
printf("ei substring occured %d %s.\n", ei_cnt,
ei_cnt == 1 ? "time" : "times");
return 0;
}
there is the following function:
void readAndPrint(FILE * f) {
int c;
while(c = fgetc(f) != EOF) {
printf("%d", c);
}
}
In the main() body I used the following code to use the above function:
FILE * pFile;
pFile=fopen ("myfile.txt","r");
readAndPrint(pFile)
;
Whatever I put into myfile.txt, the program prints out ones.
For example, for abc, 111 is printed out.
I know that c in the function should be declared int to properly compare it to EOF. Also, I expected an int code from the ASCII set for each char in the text file to be printed out (97 for a, ...). I cannot figure out why it prints out 'ones'... Does you know the reason why? Thank you in advance.
(c = fgetc(f) != EOF) - Here first fgetc(f) != EOF this condition is happening and the result 1 or 0 is assigned to c. Always a condition check returns TRUE(1) or FALSE (0).
Do while((c = fgetc(f)) != EOF)
I'm writing a program that compares two files character by character. The function to compare each file returns a value dependant on the condition of the files.
the function returns 0 when both files are the same, -1 if both files match but the first file ends before the second, -2 if both files match but the second file ends before the first, and a positive int indicating which character the files differ at.
#include <stdio.h>
#include <string.h>
#define CMP_EQUAL 0
#define CMP_EOF_FIRST -1
#define CMP_EOF_SECOND -2
int char_cmp(FILE *fp1, FILE *fp2);
int main(void)
{
FILE *fp1;
FILE *fp2;
fp1 = fopen("input1.txt", "rb+");
fp2 = fopen("input2.txt", "rb+");
switch(char_cmp(fp1, fp2))
{
case CMP_EQUAL:
printf("The Files are equal");
break;
case CMP_EOF_FIRST:
printf("EOF on a.txt");
break;
case CMP_EOF_SECOND:
printf("EOF on t.txt");
break;
default:
printf("files differ: char %d\n", char_cmp(fp1, fp2));
break;
}
if(fclose(fp1) != 0)
{
perror("fclose");
/*other error handling*/
}
if(fclose(fp2) != 0)
{
perror("fclose");
/*other error handling*/
}
return 0;
}
int char_cmp(FILE *fp1, FILE *fp2)
{
int c, d;
size_t byte = 0;
int same = 1;
do
{
byte++;
}while((c = fgetc(fp1)) == (d = fgetc(fp2)));
if(c == EOF && d != EOF)
{
return CMP_EOF_FIRST;
}
if(d == EOF && c != EOF)
{
return CMP_EOF_SECOND;
}
if(c != d)
{
return byte;
}
return CMP_EQUAL;
}
I was wondering how i would break out of the do loop after checking if all the characters match in each file. Because when i have tried, It breaks the moment it finds a character that is the same and does not check the rest of it.
Also i've encourtered this weird bug where if one file contains:
dee
and the second one contains
ae
it gives me a weird return value and was wondering why is that so?
thanks for any help in advance
You call char_cmp(fp1, fp2)) twice - once in the switch statement, and the second time in the default condition. The second time it returns you the second char position in which they differ (or something another, really unexpected :)
Change it to
int k = char_cmp(fp1, fp2));
and use k in these both places:
switch( k )
...
printf("files differ: char %d\n", k);
EDIT: The infinite loop in case of equal files happens because in this condition:
(c = fgetc(fp1)) == (d = fgetc(fp2))
c and d become forever equal to EOF from some moment. Change it to
(c = fgetc(fp1)) == (d = fgetc(fp2) && c != EOF
and everything is ok.
You are calling char_cmp() multiple times. The second time round, in the printf() call, returns a different value from the first call because the file pointers have been used.
Call char_cmp() once and store the returned value in a local.
cmp = char_cmp(fp1, fp2);
switch(cmp)
{
case CMP_EQUAL:
printf("The Files are equal");
break;
case CMP_EOF_FIRST:
printf("EOF on a.txt");
break;
case CMP_EOF_SECOND:
printf("EOF on t.txt");
break;
default:
printf("files differ: char %d\n", cmp);
break;
}
I don't know whether the rest of your logical is correct or not.
Actually, your logic is not correct. It enters an infinite loop when presented with identical files. I'm sure you'll be able to track down the problem!
When both reach EOF at the same time, the while condition is true and you start looping over and over, since EOF == EOF.
I suggest you to try to be less "short" at the beginning.
I'm following a book on c, and I come to some code that reads a file with 3 lines of text.
#include <stdio.h>
int main (int argc, const char * argv[]) {
FILE *fp;
int c;
fp = fopen( "../../My Data File", "r" );
if ( NULL == fp ) {
printf( "Error opening ../My Data File" );
} else {
while ( (c = fgetc( fp )) != EOF )
putchar ( c );
fclose( fp );
}
return 0;
}
I tried to modify it, to detect each line and print the current line number by making these modifications.
int line = 1;
while ( (c = fgetc( fp )) != EOF ){
if (c == '\n'){
printf(" LINE %d", line);
putchar( c );
line++;
}
else {
putchar ( c );
}
}
But it failed to print the line #, till I changed the type of the variable c to a char. Is there a way to check for a newline while still using c as an int?
What is the proper way to check for a newline?
Your code prints line numbers at the end of a line, right before printing the '\n', because of the way you have written the loop. Otherwise, your code should work.
If you want your code to print the line numbers at the beginning, you can do something like (untested):
int line_num_printed = 0; /* indicating if we printed a line number */
int line = 1;
while ((c = fgetc(fp)) != EOF) {
if (!line_num_printed) {
printf("LINE %d: ", line);
line_num_printed = 1;
}
putchar(c);
if (c == '\n'){
line++;
line_num_printed = 0;
}
}
If there is something else that "doesn't work", you should post complete code and tell us what doesn't work.
Edit: The proper way to check a character for a newline is to test against '\n'. If the character came from a file, you should also make sure you open the file in text mode, i.e., without a b in the second argument to fopen().
Also, you want c to be of type int, not char. This is because in C, EOF is a small negative number, and if char is unsigned, comparing it against a negative number convert the value of EOF to a positive value (equal to EOF + UCHAR_MAX + 1 most likely). Therefore, you should not change c to char type. If you do, the comparison c != EOF might be false even when fgetc() returns EOF.
Usually the integer code for a new line ('\n') is 13. So you could do ( if (c == 13) ), but also note that windows files use 2 characters to define a new line '\r' and '\n'. The integer character for '\r' is 10. But basically yes you can keep 'c' as an int and just compare against 13.