As a programming novice I have been trying to teach myself C to better understand computers using The C Programming Language (2nd Edition).
This site has been very helpful so far in troubleshooting problems but there is one problem I can't get my head around. It is my proposed solution to exercise 1-12 using my solution to 1-9 as a backdrop. I was wondering if anyone in this online community would kindly point out where I'm going wrong.
Exercise 1-9 asks you to "Write a program to copy its input to its output, replacing each string of one of more blanks by a single blank"
There are many ways to skin the proverbial cat here but the solution that reads most simply to me is this:
int c;
while((c = getchar()) != EOF)
{
if(c == ' ')
{
putchar(' ');
while((c = getchar()) == ' ') // if there are subsequent blanks
; // do nothing
}
if(c != EOF)
putchar(c);
}
Now Exercise 1-12 is asking you to "Write a program that prints its input one word per line."
My first attempt was successful but an oversimplification of the problem.
int c;
while((c = getchar()) != EOF)
{ if(c == ' ')
putchar('\n');
else
putchar(c);
}
So I've tried to rectify this to accept a much wider range of inputs and here is the result
int c;
while((c = getchar()) != EOF)
{
if(c == ' ' || c == '\t' || c == '\n')
{
putchar('\n');
while((c = getchar()) == ' ' || (c = getchar()) == '\t' || (c = getchar()) == '\n')
;
}
if(c != EOF)
putchar(c);
}
Now I know this is wrong when I run it and I have looked up online other very simple ways to solve the problem.
My issue here is that I don't understand why it doesn't work. To me if the solution to 1-9 works I don't understand why it fails when I take the same principle to 1-12. Anyone who could point this out would be appreciated!
What you did was almost correct, but getchar() consumes one character of input on every invocation.
You could have written
while ((c = getchar()) == ' ' || c == '\t' || c == '\n')
because the || operator is processed left-to-right with so called sequence point in between;
though clearer is to move the initialization of c out of the loop condition.
Finally, using isspace this would consume any whitespace characters, with much less typing:
#include <ctype.h>
int c;
do {
c = getchar();
} while (isspace(c));
while((c = getchar()) == ' ' || (c = getchar()) == '\t' || (c = getchar()) == '\n')
^ ^ ^
You're calling getchar() three times. Those calls read three characters, and you compare the first against space, second against \t and third against \n. (The calls are separated by ||, so there should be no issues with undefined sequencing.)
Instead, use temp variable:
int c;
do {
c = getchar();
} while (c == ' ' || c == '\t' || c == '\n');
Using isspace() from ctype.h would probably be better too.
It might be worth mentioning a sane and readable way to write this code without "assignment inside conditions", "most operators on a single line wins a price" or other such bad and dangerous habits picked up from that old book:
#include <stdio.h>
#include <ctype.h>
int main (void)
{
while(1)
{
int c = getchar();
if (isspace(c))
{
putchar('\n'); // at first space found, print line feed
do
c = getchar();
while(isspace(c)); // discard any additional spaces
}
if(c == EOF) // here c will not be a space, but possibly EOF
{
break;
}
putchar(c);
}
return 0;
}
If your char is not a space then you will try to get another char from the user instead of analyzing the one that was entered.
correct your while to call it only once:
while ((c = getchar()) == ' ' || c == '\t' || c == '\n')
I'm reading K&R's book on C and i got to this part where the output would be the number of newlines that you input.I wanted to make it so that it prints out each number corresponding to the amount of newlines typed as the lines are being read.This only outputs the value of nl after F6 or CTRL+Z has been pressed(EOF).Could someone explain to me why?
int main(){
int c, nl = 0;
while ((c = getchar()) != EOF)
if (c == '\n')
++nl;
printf("%d\n", nl);
}
You forgot some brackets. Here's what your code does currently:
int main(){
int c, nl = 0;
while ((c = getchar()) != EOF){
if (c == '\n'){
++nl;
}
}
printf("%d\n", nl);
}
Here's what you probably wanted to do based of indentation:
int main(){
int c, nl = 0;
while ((c = getchar()) != EOF){
if (c == '\n'){
++nl;
printf("%d\n", nl);
}
}
}
In C, whitespace is mostly ignored. If you want to run multiple statements together in a block, you need to surround that code with brackets {}
The while loop ends only when the character is an EOF character. EOF is a special character that represents the end of the file the program is reading. Since you are reading from the console, the console itself is the file you are reading from but it as no end. However in your system you can send an EOF character to the console by typing F6 or CTRL+Z
Instead if you want to print the number of lines while typing you should change your code like this:
int main(){
int c, nl = 0;
while ((c = getchar()) != EOF){
if (c == '\n'){
++nl;
printf("%d\n", nl);
}
}
}
I am trying to write a program which replaces a string of one or more tabs by a single tab.
Here's what I wrote:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int c;
while ((c = getchar()) != '\n')
{
if (c == 9)
{
while((c=getchar())== 9)
putchar(' ');
if (c != 9)
break;
}
putchar(c);
}
}
I compared it to newline because I don't get EOF and pressing ctrl-z does nothing, atleast on Windows.
Well the output prints spaces instead of tabs. Can someone point out what am I doing wrong?
There is no need to break, in fact, when you use break inside a for/while you exit from the loop (not what you want), if you want to allow only one tab use a sentinel and continue if the previous character is also a tab:
int c, tab = 0;
while (((c = getchar()) != '\n') && (c != EOF)) {
if (c == '\t') {
if (tab == 1) continue;
tab = 1;
} else {
tab = 0;
}
putchar(c);
}
Press CTRL+ Z + Intro to send EOF in Windows.
its because you write putchar(' ').
its an error. write putchar('\t') instead.
there is no such char as ' '. this is 4 spaces.
I'm asked to write a simple program to "format" text based on the well-known loop:
int c;
while ((c = getchar()) != EOF)
putchar(c);
The program reads from stdin & writes to stdout & should be tested using I/O redirection.
Each tab in the input is replaced by a space & then two or more consecutive spaces are replaced by a single space in the output.
Two or more consecutive blank lines in the input are replaced by one blank line in the output.
Note: newline character is the last character of a line rather than the first character of the following line.
Here is what I have so far, but the multiples spaces, newlines and tabs I have in my input text file aren't getting replaced in the output text file:
#include <stdio.h>
int main (void){
int c;
int spacecount = 0;
int newlinecount = 0;
while ((c = getchar()) != EOF){
if (c == '\n'){
if (++newlinecount < 3){
putchar(c);
}
continue;
}
newlinecount = 0;
if (c == ' '){
if (++spacecount < 2){
putchar(c);
}
continue;
}
spacecount = 0;
if (c == '\t'){
c = ' ';
}
putchar(c);
}
return 0;
}
Remove All Blank Lines & Compressing All Tab & Spaces to 1 Space
The biggest problem you have is if you encounter a ' ' or a '\n' where you need to replace multiple occurrences of either with a smaller number, you need to keep reading (at that point within your outer while loop) until you find a character that is not a ' ' or a '\n'. That simplifies keeping track of your counts. (and eliminates the need for spacecount and newlinecount)
Since you are testing against multiple characters, when you find the first character that does not match your current search character, simply put it back in stdin and move to the next iteration of your outer while loop.
When compressing all tabs and spaces to a single space, you need to test for either a tab or space in a single if statement.
Putting that together, you can do:
#include <stdio.h>
int main (void) {
int c;
while ((c = getchar ()) != EOF)
{
if (c == '\r') continue;
if (c == '\n') { /* handle newlines/carriage-returns */
putchar (c);
while ((c = getchar ()) == '\n' || c == '\r') {}
if (c != EOF) ungetc (c, stdin); else break;
continue;
}
if (c == ' ' || c == '\t') { /* spaces & tabs */
putchar (' ');
while ((c = getchar ()) == ' ' || c == '\t') {}
if (c != EOF) ungetc (c, stdin); else break;
continue;
}
putchar (c);
}
return 0;
}
(note: the code was updated to handle DOS/windoze \r\n line endings as well as Linux '\n')
Example Input
$ cat dat/gcfmt.txt
N <tab> description
21 grapes
18 pickles
N <spaces> description
23 apples
51 banannas
<spaces>N<tab> description
8 cherries
4 mellons
6 strawberries
that's all folks <tab separated>
that's all folks <space separated>
Exampe Use/Output
Using the same input file, the output is now:
$ ./bin/gcfmt1 <dat/gcfmt.txt
N <tab> description
21 grapes
18 pickles
N <spaces> description
23 apples
51 banannas
<spaces>N<tab> description
8 cherries
4 mellons
6 strawberries
that's all folks <tab separated>
that's all folks <space separated>
Let me know if that is what you intended.
I've been reading "The C Programming Language" and I got to this part of inputs and outputs.
I've read other threads saying that the console doesn't recognize enter as EOF. So that I should use CTRL + Z in Windows or CTRL + D in Unix (neither of those is working for me).
I also read other people asking the same saying they could make it work, the problem in their codes was syntax not the program not terminating.
Is there another solution?
This is the code:
#include <stdio.h>
main()
{
int nb, nl, nt, c;
nb = 0;
nl = 0;
nt = 0;
while ((c = getchar()) != '\n') {
if (c == ' ')
++nb;
else if (c == '\n')
++nl;
else if (c == '\t')
++nt;
}
printf("Input has %d blanks, %d tabs, and %d newlines\n", nb, nt, nl);
}
Edit: The \n was supposed to be an EOF, I was messing around before I posted and I forgot I changed it :P
It doesn't work with EOF neither, I just skipped that one.
while ((c = getchar()) !=EOF) {
}
Then use Ctrl+Z or F6 on Windows
Following will wait for either a \n or EOF, which comes first
while((c = getchar()) != '\n' && c != EOF){
}
On Windows, you type Ctrl-Z on a line by itself (no spaces or anything) and type the Return after that. On Windows, you could technically skip the EOF indicator and keep reading characters, though this doesn't apply to other operating systems because EOF actually means EOF.
while ((c = getchar()) != '\n'){
if (c == ' ')
++nb;
else if (c == '\n')
++nl;
else if (c == '\t')
++nt;
}
According to the condition in your while loop, you will not be able to count number of new lines because you will stop the while loop when the user inputs a new line character ('\n')
Other than that, counting blanks and tabs just works fine.
CTRL+Z will be recognized as a EOF in windows. But in order to recognize it in your program, use condition in while loop as ((c = getchar()) != EOF).
Now when the user presses the key combination: CTRL+Z, It will input to console as EOF, and the program should recognize it as a character input.
Doing this will allow you to count number of lines in the input
So, my suggestion is:
while ((c = getchar()) != EOF){
if (c == ' ')
++nb;
else if (c == '\n')
++nl;
else if (c == '\t')
++nt;
}
If you are on a unix system, the only way to simulate EOF via keyboard while feeding input to the program manually is to press CTRL+D
Here are a couple methods of feeding input to your program and be able to signal EOF at the end of the input:
Make use of the here string format to feed a string representation of a file to the program.
./myprog <<< "Here is a string to work with"
Alternatively, you can also use input redirection to feed a file containing the input to the program.
./myprog < input.file
Any of the above listed methods will work with the following code:
#include <stdio.h>
#ifndef EOF
#define EOF (-1)
#endif
int main(void)
{
int nb, nl, nt, c;
nb = 0;
nl = 0;
nt = 0;
while ((c = getchar()) != EOF){
if (c == ' ')
++nb;
else if (c == '\n')
++nl;
else if (c == '\t')
++nt;
}
printf("Input has %d blanks, %d tabs, and %d newlines\n", nb, nt, nl);
return 0;
}
Not to leave windows out of the game. To simulate EOF on keyboard on windows, use CTRL+Z key combination
Not sure if the here-string format for unix is available for windows, but input redirection should be similar
/* This program will calculate the number of blanks, tabs and new line in a text stream */
#include <stdio.h>
main ()
{
int c,nl = 0, blank = 0, tab = 0; //Newline, blanks and tabs.
while ((c = getchar()) != EOF) {
if (c == '\n')
++nl;
else if (c == '\t')
++tab;
else if (c == ' ')
++blank;
}
printf("Tabs = %d\nBlanks = %d\nNewLine = %d",tab, blank, nl);
}
I wrote this following code and it works properly on Ubuntu. As it is similar to what you wrote, I tried the code and Ctrl-D is working properly in UNIX.
I tested the following code and have realized that if we input \n in text stream it will not increase the counter of the new line, same goes for a \t tab. Only pressing enter for new line and pressing tab for tab is counted by the counter this is a point to be noted.
This is happening because pressing enter actually puts a newline character which is a single character whereas entering \n is treated as differently and they are actually two characters.
I thought this will add value to this question so I explained this thing too.
Thanks.
Change the line
// Buggy, you want calculate the # of '\n' in loop body,
// so logically you shouldn't use it as a stop condition.
while ((c = getchar()) != '\n')
to
while ((c = getchar()) != EOF)
And try press Ctrl + C in your console window on Windows. It works on my platform which is running Win7.
First of all press Ctrl + Z which will print ^Z then press Enter to go to EOF..
I had the same problem, so I check the value of ctrl+D by debugging my code and I found that the value of ctrl+D is 255 and I replaced the EOF with 255, and thats worked for me, if its not working for you try to figure out the value of ctrl + D in Unix.
#include <stdio.h>
main()
{
int nb, nl, nt, c;
nb = 0;
nl = 0;
nt = 0;
while ((c = getchar()) != 255) {
if (c == ' ')
++nb;
else if (c == '\n')
**++nl;**
else if (c == '\t')
++nt;
}
printf("Input has %d blanks, %d tabs, and %d newlines\n", nb, nt, nl);
}
To recognize EOF in Turbo C++, in the terminal window press Ctrl+z; this will act as EOF in the program and then terminate the program....with the condition:
while ((c = getchar()) != EOF)