Kernighan & Ritchie code example confusion - c

Is there any reason of the second 'c = getchar()' mention in this code example?
#include <stdio.h>
/* copy input to output; 1st version */
int main(void) {
int c;
c = getchar();
while (c != EOF) {
putchar(c);
c = getchar(); // <-- I mean this one.
}
return 0;
}

c = getchar(); //read for the first time before entering while loop
while (c != EOF) {
putchar(c);
c = getchar(); // read the next input and go back to condition checking
}
return 0;
first getchar() reads the first time input character.
second getchar() keeps on reading next input(s), untill a EOF
In other words, the purpose of while (c != EOF) is to keep on checking whether the c is EOF or not. if c is not changed, then the while() loop is meaningless, isn't it? The second getch() is responsible for chnaging the value of c in each iteration.

yes, so it wont putchar EOF.
It reads the first character, checks that its not EOF, then putChars it, then gets another char, back to the top of the while loop and checks its not EOF.

The second c = getchar() is to read another char and yet anther one until EOF is met.

first c = getchar(); will only work Once, but c = getchar(); inside while loop will work every time until c != EOF.
c = getchar(); // Read value of `c` if `c != EOF` it will enter while loop else it will exit
while (c != EOF) { // checking condition
putchar(c); //printing value of c
c = getchar(); // again getting new value of c and checking in while loop,
//if condition is true it will continue, else it will exit
}

It's there because a while loop tests at the top but you really need the test in the middle. An alternative to duplicating code above the loop and inside it, is using break.
while (1) {
c = getchar();
if (c == EOF) break; /* test in middle */
putchar(c);
}

That's my inattention. I was running in terminal this version of code:
while((c = getchar()), c != EOF) {
putchar(c);
}
and couldn't see the difference between results. Stupid situation.
Thanks to all anyway.

Related

getchar() stuck in a loop never reaching the EOF

#include <stdio.h>
int main() {
int c;
while(getchar() != EOF) {
if (getchar() == ' ') {
c++;
}
printf("%i", c);
}
}
I realized that typing in a sentence like the one you're reading right
I\nrealized\nthat\ntyping\nin\n\a\n ...
i believe that's how it's being read, getchar() does not reach the EOF to make the condition in the while parentheses false..
my goal here is to make a program that takes in input from me..
reads it
if there are any spaces
it counts on a counter
when EOF is reached
the condition to keep reading it becomes false
the counter value gets printed out on the screen
to show me how many spaces i had in my entire input..
is it impossible? is that why people just use scanf() ?
this is the output i get when trying something
user#user:/c# ./a.out
hello stackoverflow this does not do what i want it to
001111111222223344445666677
You need to put the result of getchar() into a variable:
int ch;
while ((ch = getchar()) != EOF)
You shouldn't call getchar() a second time to check if it's a space, since that will read a second character so you'll be testing every other character, just compare the variable:
if (ch == ' ')
And if you want to see the total number of spaces, put the printf() at the end of the loop, not inside it.
So the whole thing should look like:
#include <stdio.h>
int main() {
int counter=0;
int ch;
while((ch = getchar()) != EOF) {
if (ch == ' ') {
counter++;
}
}
printf("%i\n", counter);
}
To send EOF from the terminal, type Control-d on Unix, Control-z on Windows.

Reading text file from stdin stops at last line

I wrote a short program to test reading text files from stdin:
int main(){
char c;
while(!feof(stdin)){
c = getchar(); //on last iteration, this returns '\n'
if(!isspace(c)) //so this is false
putchar(c);
//remove spaces
while (!feof(stdin) && isspace(c)){ //and this is true
c = getchar(); // <-- stops here after last \n
if(!isspace(c)){
ungetc(c, stdin);
putchar('\n');
}
}
}
return 0;
}
I then pass it a small text file:
jimmy 8
phil 6
joey 7
with the last line (joey 7) terminated with a \n character.
My problem is, after it reads and prints the last line, then loops back to check for more input, there are no more characters to read and it just stops at the line noted in the code block.
Question: The only way for feof() to return true is after a failed read as noted here: Detecting EOF in C. Why isn't the final call to getchar triggering EOF and how can I better handle this event?
There are multiple problems in your code:
You do not include <stdio.h>, nor <ctype.h>, or at least you did not post the whole source code.
You use feof() to check for end of file. This is almost never the right method, as underscored in Why is “while ( !feof (file) )” always wrong?
You read the byte from the stream in a char variable. This prevents proper testing for EOF and also causes undefined behavior for isspace(c). Change the type to int.
Here is an improved version:
#include <stdio.h>
int main(void) {
int c;
while ((c = getchar()) != EOF) {
if (!isspace(c)) {
putchar(c);
} else {
//remove spaces
while ((c = getchar()) != EOF && isspace(c)) {
continue; // just ignore extra spaces
}
putchar('\n');
if (c == EOF)
break;
ungetc(c, stdin);
}
}
return 0;
}
While your method with ungetc() is functionally correct, it would be better to use an auxiliary variable this way:
#include <stdio.h>
#include <ctype.h>
int main(void) {
int c, last;
for (last = '\n'; ((c = getchar()) != EOF; last = c) {
if (!isspace(c)) {
putchar(c);
} else
if (!isspace(last))
putchar('\n');
}
}
return 0;
}

C - Reading from a file issue with the last line

The expected input to my program for my assignment is something like
./program "hello" < helloworld.txt. The trouble with this however is that I must analyse every line that is in the program, so I have used the guard for the end of a line as:
while((c = getchar()) != EOF) {
if (c == '\n') {
/*stuff will be done*/
However, my problem with this is that if the helloworld.txt file contains:
hello
world
It will only read the first line(up to the second last line if there were to be more lines).
For this to be fixed, I have to strictly make a new line such that helloworld.txt looks something like:
hello
world
//
Is there another way around this?
Fix your algorithm. Instead of:
while((c = getchar()) != EOF) {
if (c == '\n') {
/* stuff will be done */
} else {
/* buffer the c character */
}
}
Do:
do {
c = getchar();
if (c == '\n' || c == EOF) {
/* do stuff with the buffered line */
/* clear the buffered line */
} else {
/* add the c character to the buffered line */
}
} while (c != EOF);
But please note that you shouldn't use the value of the c variable if it is EOF.
You need to re-structure your program so it can "do stuff" on EOF, if it has read any characters since the previous linefeed. That way, a non-terminated final line will still be processed.

Write a program that reads input up to # and reports the number of times that the sequence ei occurs

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;
}

K&R: Chapter 6 - Why getword() function does not read EOF?

This is my very first post on Stack Overflow, so I hope I don't step on anyone's toes.
Of course, all inputs are welcome and appreciated, but those most suited to answer would have actually read the book, C Programming Language, 2nd ed.
I have just finished coding Exercise 6-4, but I cannot seem to figure something out. Why does the getword() function not read EOF until I press Ctrl+D (I code in C in an Arch Linux VM)?
Many of my previous exercises from the book require reading from stdin. One way I would do it is via something like
while ((c = getchar()) != EOF) {...}
In such an instance, I never have to press Ctrl+D. I enter in my input, press Enter, the stdin buffer gets flushed out, and EOF is detected automatically. The getword() function also relies on getchar() at its base, so why does it hang my program?
The getword() function is called from main():
while (getword(word, MAX_WORD) != EOF) {
if (isalpha(word[0])) {
root = addtree(root, word);
}
}
The getword() function itself:
int getword(char *word, int lim) {
char *w = word;
int c;
while (isspace(c = getch())) {
}
if (c != EOF) {
*w++ = c;
}
// This point is reached
if (!isalpha(c)) {
// This point is never reached before Ctrl+D
*w = '\0';
return c;
}
for ( ; --lim > 0; w++) {
if (!isalnum(*w = getch())) {
ungetch(*w);
break;
}
}
*w = '\0';
return word[0];
}
I put comments to indicate the point where I determined that EOF is not being read.
The getch() and ungetch() functions are the same ones used in the Polish notation calculator from Chapter 4 (and that program was able to read EOF automatically - by pressing Enter):
#define BUF_SIZE 100
char buf[BUF_SIZE];
int bufp = 0;
int getch(void) {
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c) {
if (bufp >= BUF_SIZE) {
printf("ungetch: too many characters\n");
}
else {
buf[bufp++] = c;
}
}
Thus far, this is the first program I wrote since the beginning of this book that requires me to manually enter the EOF via Ctrl+D. I just can't seem to figure out why.
Much appreciation in advance for explanations...
Having to type Ctrl+D to get EOF is the normal behavior for Unix-like systems.
For your code snippet:
while ((c = getchar()) != EOF) {...}
pressing Enter definitely shouldn't terminate the loop (unless your tty settings are badly messed up).
Try compiling and running this program:
#include <stdio.h>
int main( void )
{
int c;
while ((c = getchar()) != EOF) {
putchar(c);
}
return 0;
}
It should print everything you type, and it should terminate only when you type control-D at the beginning of a line (or when you kill it with control-C).
The 'not reached' point would only be reached if you did something like type a punctuation mark in the input - or you read EOF. If you type a letter, or spaces, then it is bypassed.
When input is coming from a terminal (standard input), then EOF is not detected until you type Control-D (or whatever is specified in the stty -a output) after you enter a newline, or after you hit another Control-D (so two in a row). The code reads through newlines because the newline character '\n' satisfies isspace().
The source of my confusion vis-a-vis my previous programs was that the effect of my previous programs were always printed to stdout inside the while loop, so I always immediately saw the result without needing to feed in EOF. For this one, the tree is not printed until after the while loop ends, so the EOF encounter was needed. I failed to recognize that, and that's why I was going insane.
Thanks again for setting me straight!

Resources