K&R Exercise 1-9 solution C programming - c

The task is to make a C program that replaces multiple blanks with a single blank and I found this solution on another StackOverflow question:
int c;
while ((c = getchar()) != EOF) {
if (c == ' ') {
while ((c = getchar()) == ' ')
;
putchar(' ');
if (c == EOF) break;
}
putchar(c);
}
It works but I am puzzled by the second while loop:
while ((c = getchar()) == ' ')
;
How does line this even remove any white spaces? I thought it just does nothing until it comes across another non-blank character. So then if a sentence had 4 blanks then I would expect it to turn into 5 blanks because your just adding another blank with putchar(' ') ? Does it remove the excess blank spaces in a way I'm not aware of?

while ((c = getchar()) == ' ')
;
This bit skips over spaces. After skipping all of them,
putchar(' ');
puts one space.
This replaces groups of spaces with one.

The program reads (using getchar) a string from standard input and the outputs (using putchar) the same string to standard output but leaving out the excess spaces. So effectively it "removes" the extra spaces.
The while loop skips over a consecutive block of whitespace in the input while outputting nothing, and then after the loop is done, outputs a single space. That's how it "removes" the spaces.

getchar reads one character at a time. At each iteration it reads a character and check if it is a space or not. If the character read is a space then read another one until it finds a non-white-space character. After break out of loop putchar(' '); is executed and prints a space.

Related

I don't understand how how this code works

I'm doing Exercise 1-9 in the K&R Book, while trying to find solutions I came across this code:
int main()
{
int c;
while ((c = getchar()) != EOF) {
if (c == ' ') {
while ((c = getchar()) == ' ');
putchar(' ');
if (c == EOF) break;
}
putchar(c);
}
}
Why does the first if statement work if even if I input a letter. From my understanding it will only execute if the character I input is a blank space?
Btw the exercise is making a program replace multiple consecutive blank spaces to a single one.
This program prints any entered character except the blank character ' ' until the user will interrupt the input.
In this while loop
while ((c = getchar()) == ' ');
each blank character is read but not outputted. And after the loop only one blank character is outputted
putchar(' ');
That is the program removes adjacent blank characters leaving only one blank character in the input sequence of characters entered by the user.
I've formatted out and comented the code. Hope that'll help. The code actually covert all
sequence of spaces within stdin into one space:
"123 456 a b c " -> "123 456 a b c "
Code:
int main() {
int c;
/* we read stdin character after character */
while ((c = getchar()) != EOF) {
/* if we have read space */
if (c == ' ') {
/* we skip ALL spaces */
while ((c = getchar()) == ' ')
; /* skipping ALL spaces: we do nothing */
/* and then we print just ONE space instead of many skipped */
putchar(' ');
/* if we at the end of stdin, we have nothing more to print */
if (c == EOF)
break;
}
/* we print every non space character */
putchar(c);
}
}
It loops as long as the input stream doesn't end (EOF = End Of File).
If the entered character is a space, it will ignore any follow-up spaces and only print one space afterwards.
Otherwise it will output the entered character.
int main()
{
int c;
while ((c = getchar()) != EOF) {
For each character of input...
if (c == ' ') {
...if the character is a space...
while ((c = getchar()) == ' ');
... this loop skips all spaces that come after the first... See the semicolon in the right, that makes it read the character, check that it is a space, and does nothing with it. It is a very tricky thing to write it as such, as it is quite common to think that the loop body will be the next statement below, while it has no body at all. After a while loop, you can assume that the condition that let you enter the loop is false, so we have some true assertion: in c there's for sure no space stored (it can still be EOF, which is not a character, so we need to test for it before printing, and we do it next, after the next statement)
putchar(' ');
... after the loop, only a single space is output, corresponding to the one tested in the first if statement you mentioned in your question. Think that c is not a space character (so we cannot putchar(c);), as we skip all spaces until none remained. Still it can be an EOF indicator, that is checked below.
if (c == EOF) break;
if the character was not a space, it could only be an EOF indicator. In that case, we need to get out of the loop so we don't print it, in the next statement...
}
putchar(c);
... as we have been reading characters in c until we got a non space (nor an EOF indicator, as we got out of the loop above in that case) we need to print that char anyway. This putchar(c); statement will always print a non-space character. It is out of the if statement, as it must be done for all the characters that were initially nonspaces and the characters that followed a sequence of spaces.
}
...As above, we can assume the test condition of the loop is false, so here we can ensure that c has got EOF (but only because the break statement inside the loop also happens when c == EOF).
}
Et voila!!!
Note
while trying to find solutions I came across this code:
A final note, it is better for you if you post your attempt at programming a solution, instead of finding already made solutions by searching. You'll learn more on programming and less on googling, which IMHO is not your primary interest.

Why should we track the inside of the word in K&R Exercise 1-11?

Here is the exercise:
Write a program that prints its input one word per line.
My solution to this exercise is the following:
main() {
int c;
while((c = getchar()) != EOF) {
if(c == ' ' || c == '\t' )
putchar('\n');
else
putchar(c);
}
}
}
According to this link
it is a bad solution, but I'm not sure I understand why.
I would appreciate some help understanding this.
The problem is when your input contains more than one newline, tab or space in subsequent order.
Then it always jumps into a new line, although it shouldn't.
The requirement of to "print one word per line" is not fulfilled then.
You need to keep an eye on whether the newline, tab or space occurs after a sequence of non-instruction characters or not. So we need a "STATE" parameter which documents the current state.
Chrismath's solution covers that:
// print input one word per line
#define IN 1
#define OUT 0
int main (void)
{
int c, state;
// start without a word
state = OUT;
while ((c = getchar()) != EOF) {
// if the char is not blank, tab, newline
if (c != ' ' && c != '\t' && c != '\n') {
// inside a word
state = IN;
putchar(c);
// otherwise char is blank, tab, newline, word ended
}
else if (state == IN) {
state = OUT;
putchar('\n');
}
}
return 0;
}
The newline is only printed when state is IN which means at least a word of one character was printed in a line before it get to another one.
Someone could argue that a word wouldn't be a single character, but then we would need an explicit requirement of how many characters at least a word is consisted of, but this isn't provided to the task here, so the one character word is plausible and legit.
After comparing a few answers, the difference between the solution i have written above versus the correct solution in the link in the question is that a newline is not created for each blank, tab or newline character. The correct answer checks whether it has already accounted for a space and output the corresponding newline and doesn't output another newline if there is another space, thus answering the problem of "one word per line"

C- K&R exercise 1-9

looking for exercise 1-9 from the K&R book (Copy input to output. Replace each string of multiple spaces with one single space) I found this code on this site.
#include <stdio.h>
main()
{
int ch, lch;
for(lch = 0; (ch = getchar()) != EOF; lch = ch)
{
if (ch == ' ' && lch == ' ')
;
else
putchar(ch);
}
}
The program works, but the operation is not clear to me:
what is the variable lch for? Why not inserting it inside the third condition of for loop and if statement the program does not give the correct output?
You need to substitute several spaces with one space. So if the previous inputted character was space and the current inputted character is also space when you need to skip the current character.
So lch stores the value of the previous inputted character. Initially when there was not yet any input lch is set to 0. Then in each iteration lch is set to the current inputted character that in this if statement
if (ch == ' ' && lch == ' ')
whether the current character and the previous character are both spaces. If so then the program outputs nothing.
lch is getting the old character, so the ch is getting getchar(), run the loop, and when this is finished, the value is taken by lch.

Working of getchar and putchar or example in The C language 2nd Edition

CODE 1:
#include <stdio.h>
int main()
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
return 0;
}
CODE 2:
#include<stdio.h>
main( )
{
int c,d;
c=getchar();
d=getchar();
putchar(c);
putchar(d);
}
1) If
Input : bo
Output : bo
I got to know this in 2nd program that it stores both in variables c and d but where does it stores them in 1st program.
2)Pl. explain the working of first program why it repeats any word despite of its length that is more than one character.
3) From book i got to know that EOF is encountered whenever I enter or there is some error but even if I press enter this program doesn't stops but it prints nextline character again.
For question one, it stores them in c (but only one at a time). The code, better indented, is:
while ((c = getchar()) != EOF)
putchar(c);
so you can see that, for each character input into c, it outputs it as well. Keep in mind that syntax is the short form for:
c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
so you can see each iteration of the loop gets the next character.
The second question, I assume you're asking why it works for any length input. That's because it doesn't care about the length. It's simply storing and echoing each individual character.
You could give it a billion characters if you like.
As to the third, you get back EOF for an error or end of file (CTRL-Z at the start of a line for Windows, usually CTRL-D under UNIX-like operating systems, unless you have some weird terminal characteristics set up).
If you were only interested in a line, you could use something like:
while ((c = getchar()) != '\n')
putchar(c);
putchar ('\n');
while ((c = getchar()) != EOF)
Reads the value from stdin until it encounters EOF(End Of File). So the same variable c stores different values read in different iterations.
In the second example only two variable ( of char type ) are there so it can read and store only two characters.

Scanning a single char into an array C Programming

I am having a problem scanning chars into an array. Every time I do it will skip the next scan and go to the next. I know what is happening because the input also adds '\n' to the input but I do not know how to remedy the cause of it. Here is some sample code:
char charray [MAX], ffs;
int inarray [MAX], i;
for (i = 0; i < MAX; i++)
{
charray[i] = getchar();
printf ("%c\n",charray[i]);
scanf ("%d", &inarray[i]);
printf ("%d\n",inarray[i]);
}
You can do like this.
while((c = getchar()) != '\n')
{
putchar(c);
}
this may solve your problem. or you can go till EOF also.
You are reading from the standard input with 2 functions: getchar() and scanf(). You need to understand how they work.
getchar() is easy: it returns the next available character in the input stream (or waits for one or returns EOF)
scanf("%d", ...) is more complex: first, it optionally discards whitespace (spaces, enters, tabs, ...), then it reads as many characters as possible to represent an integer, and stops at the first character that can't be used for integers, like a '\n'.
As you have them in a loop, your getchar() call will get the character that stopped the scanf() and the next scanf() will procedd from there.
If your input is something like "q1w22e333r4444" (with MAX == 4), your program will work.
If your input is something like
q 1
w 22
e 333
r 4444
after the first time through the loop (where charray[0] gets 'q' and inarray[0] gets 1), the getchar() will get '\n' leaving the 'w' "ready" for scanf, which of course fails ... and is then "caught" by the next getchar(); and the "22" gets assigned in the 3rd time through the loop (to inarray[2]).
So, you need to review your code.
Also, scanf() returns a value. Use that value
if (scanf("%d", &inarray[i]) != 1) /* error */;
You should actually scan a string into the array directly, rather than characters using scanf("%s",&charray);
However your code will work if you add a while(getchar() != '\n' ); statement. This will get all characters till the '\n'.
charray[i] = getchar();
do{
c = getchar();
}while(c != '\n' && c!= EOF);
printf ("%c\n",charray[i]);
scanf ("%d", &inarray[i]);
do{
c = getchar();
}while(c != '\n' && c!= EOF);
printf ("%d\n",inarray[i]);

Resources