Reading character by character from a file in C - c

I wrote the following program :
int main(){
char str[500],c;
FILE *f1=fopen("input.txt","r");
FILE *f2=fopen("output.txt","w");
while(c=fgetc(f1)!=EOF)
fputc(toupper(c),f2);
fclose(f1);
}
I was not getting the desired result though.
I rewrote the code using a do while loop.
int main(){
char str[500];
FILE *f1=fopen("input.txt","r");
FILE *f2=fopen("output.txt","w");
char c;
do
{
fputc(toupper(c),f2);
c=fgetc(f1);
}while(c!=EOF);
}
I figured out that the reason the first code fails is because in the while loop
while(c=fgetc(f1)!=EOF), we cannot guarantee that the left part of != is evaluated first and hence the results are not proper. Is this correct the explanation?

Yes you are correct; in your first code your while loop is written wrongly:
while(c=fgetc(f1)!=EOF)
Should be:
while((c=fgetc(f1))!=EOF)
// ^ ^ added parenthesis
Because the precedence of operator != is greater than = operator in conditional expression c=fgetc(f1)!=EOF, the first returned the result of comparing the value from fgetc() with EOF (either 0 or 1) and assigned that to c. (That means simply c=fgetc(f1)!=EOF expression is equivalent to c=(fgetc(f1)!=EOF) and this is not what you need.)
You need () to overwrite precedence as I suggested.
But you have second thing to improve that is c variable must be an int (not char) in order to hold an EOF-value.
A very good Read: Definition of EOF and how to use it effectively

I will add a little why c should be int, not char. Suppose you write
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
int main(){
setlocale(LC_ALL,"");
FILE *f1=fopen("input.txt","r");
FILE *f2=fopen("output.txt","w");
char c;
while(EOF != (c=fgetc(f1))){
if(isalpha(c)) c = toupper(c);
fputc(c,f2);
}
return 0;
}
And your input.txt is
some text
Некоторый текст
Ъ - on this letter program will stop
in KOI8-R symbol Ъ have code 255 == -1 (when you use char).
That's why in case of using char instead of int will give your output.txt with only that text:
SOME TEXT
НЕКОТОРЫЙ ТЕКСТ
As for non-working code with parentheses: c=fgetc(f1)!=EOF could be denote by compiler as c = (fgetc(f1)!=EOF), that's why it's better always to add parentheses.
I recommend you to use flags -Wall -Werror when compiling your applications. In that case "forgetting" of parentheses would give you an error:
11.c: In function 'main':
11.c:9:2: error: suggest parentheses around assignment used as truth value [-Werror=parentheses]
cc1: all warnings being treated as errors

Related

C program to check for presence of ternary operator

I am unable to find out if the ternary operator is present or not through following code.. Plz help.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
void one();
int main()
{
FILE *fp;
fp=fopen("C:/Users/HP/Documents/NetBeansProjects/CD2/1.txt","r");
char c;
void one()
{
char c;
while((c=fgetc(fp)!=EOF))
{
if(c==':')
{
printf("\nThe ternary operator present");
return;
}
}
}
while((c=fgetc(fp))!=EOF)
{
printf("\n-->%c",c);
if(c=='?')
{
one();
}
}
return 0;
}
I want to know why this code doesn't work and say if the ternary operator is present or not in file 1.txt
The output shows all characters till '?' if we print them, but why it's not finding for a colon ':' ?
The exit condition of the while loop may be the problem. = has lesser precedence than != operator. So
(c=fgetc(fp)!=EOF)
gets evaluated like
(c= (fgetc(fp)!=EOF) )
See this for the precedence of various operators in C.
You could do
while((c=fgetc(fp))!=EOF)
instead. First assign the return value of fgetc() to c and then do the comparison.
ie, the variable c gets the result of the comparison which means the value is either 0 or 1.
Your program should be checking for the ? and the other operands as well.
See this.
A simple check may not be enough for cases like the 'operator' being part of a string like
char str[]="the ternary operator is ?:";
Checking for the occurrence in such cases is a bit complex.
Edit:
As Jens pointed out, fgetc() returns an int not a char. So make c an int instead of a char.
See this post.

Comparing characters in C

I have a question about comparing a single char of a string in C inside a function.
The code looks like this:
int fq(char *s1){
int i;
for(i=0;i<strlen(s1);i++){
if(s1[i]=="?"){
printf("yes");
}
}
return 1;
}
Even if s1="???" it never prints out yes. I have managed to solve the problem but i am curious as to why it works one way but not the other.
This is the piece of code that works:
int fq(char *s1,char *s2){
int i;
char q[]="?";
for(i=0;i<strlen(s1);i++){
if(s1[i]==q[0]){
printf("yes");
}
}
return 1;
}
Because the first sample compares addresses instead of characters.
There is no string type in c and the == operator when applied to an array or a pointer, compares the addresses instead of the contents.
Your function would be correctly written like this
int fq(char *s1,char *s2)
{
int i;
for (i = 0 ; s1[i] ; ++i)
{
if (s1[i] == 'q')
printf("yes");
}
return 1;
}
you can compare s1[i] to 'q'.
"?" Isn't a char but a string with just one char
'?' Is a char and should return true in s1[i] == '?'
if(s1[i]=="?"){
is not the right syntax to check whether s1[i] is the character '?'. It needs to be:
if(s1[i] == '?'){
You might want to investigate how you can change your compiler settings so that you get warnings when such expressions exist in your code base.
Using the option -Wall with gcc, I get the following message:
cc -Wall soc.c -o soc
soc.c: In function ‘fq’:
soc.c:7:15: warning: comparison between pointer and integer
if(s1[i]=="?"){
^
soc.c:7:15: warning: comparison with string literal results in unspecified behavior [-Waddress]
In C character array i.e. string has syntax as "". For a single character the syntax is ''.
In your case: it should be: if(s1[i]=='?')
If you want to compare it in string form you need to strcmp. Because the '==' operator is not capable to compare strings in C.
To compare two strings we can use: if(!strcmp(s1,q))
And for this operation you need to add string.h header like: #include <string.h>
To compare strings with '==' operator you need to overload the operator. But, C does not support operator overloading. To do so you can use C++ language.

Unknown Logical Error Using the getc() Function in C

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.

Why these c code not working? Whats wrong with these?

#include < stdio.h >
#include < string.h >
int main()
{
unsigned char a;
FILE *P;
P=fopen("mola.txt","r");
while((a=getc(P))!=EOF)
printf("%c",a);
}
Whats wrong with these code? When I compile it gives warning "comparison is always true due to limited range of data type." What does that warning mean?
You are storing the result of getc in a char. It should be an int. There's also a C FAQ on it. Also you should check the return value of the fopen.
P=fopen("mola.txt","r");
if (NULL == P) {
perror("fopen"):
}
Also the while looks fishy. Try indenting ?
while((a=getc(P)) != EOF)
printf("%c",a);
It means just what it says
comparison is always true due to limited range of data type.
The range of the data type in question (the a, which is unsigned char) is from 0 to 255 (really UCHAR_MAX);
The EOF value is -1
You are comparing a (from 0 to 255) with -1
(a != -1)
the condition will always be true
Try:
#include <stdio.h>
#include <string.h>
int main()
{
int a;
FILE *P;
P=fopen("tryit2.c","r");
while(EOF != (a = fgetc(P))) {
printf("%c",a);
}
}
You had two problems "getc()" returns an integer not a character. And the while statement had some weird side effects in the original order.
It means the loop will fell into Infinite loop not allowing the program to exit when at a=getc(p).

What to replace in this C Puzzle?

Now this is a silly puzzle I got from some exam paper,sadly I am unable to figure it out from last 15 minutes.
#include <stdio.h>
int main(void){
/* <something> */
putchar(*(wer[1]+1));
return 0;
}
What should we replace in place of something in order to get the output e.Now we know putchar takes a int as argument but this code assumes to give a pointer.Does this question is even valid ?
const char *wer[2] = { "failed", "test" };
Since a[i] is the same as *(a + i) by definition, you can transform the putchar() argument into wer[1][1]. So, something like char *wer[2] would be a satisfactory definition, and any values such that wer[1][1] == 'e' will work.
char * wer[] = { "foobar", "he"};
First, in the code you have mentioned the argument to putchar() is
*(wer[1]+1)
which is not a pointer. It seems that wer[1] is some pointer and that address pointed by wer[1] + 1 is dereferenced. So if wer is an array of pointers to int, then putchar argument should be int which is fine.
Now the code in place of something can be
You have not mentioned clearly what does e mean, is e a char or e is 2.71... (Natural logarithm base) In either case it should be easy to get that output with this code.
-AD
An easy answer is:
char **wer;
putchar('e');
return 0;
For example, the complete code would like like:
#include <stdio.h>
int main(int argc, char **argv)
{
/* Something starts here */
char **wer;
putchar('e');
return 0;
/* Something ends here */
putchar(*(wer[1] + 1));
return 0;
}
The output is:
susam#swift:~$ gcc really-silly-puzzle.c && ./a.out && echo
e
susam#swift:~$
A more interesting question would have been: What is the shortest code that can replace /* */ to get the output 'e'?
From the very pedantic point of view, there's no correct answer to the question. The question is invalid. C language itself makes no guarantees about the output of a program if the output does not end in a newline character. See 7.19.2/2
A text stream is an ordered sequence
of characters composed into lines,
each line consisting of zero or more
characters plus a terminating new-line
character. Whether the last line
requires a terminating new-line
character is implementation-defined.
This program output to the standard output, which is a text stream. The output of this program is implementation-dependent, regardless of what you put in place of /* <something> */, meaning that the question might make sense for some specific platform, but it makes no sense as an abstract C language question.
I highly doubt though that your examiners are expecting this kind of pedantry from you :)))

Resources