I am a beginner of C language, and now trying to count the number of characters which is input.
#include <stdio.h>
main()
{
long nc;
nc = 0;
while (getchar() != EOF)
++nc;
printf("%1d\n", nc);
}
This is what I wrote just as my textbook writes, but printf function doesn't seem to work.
In addition, this program doesn't seem to finish, because the prompt is not coming up.
I have no idea if the contents of this book are old enough.
Could you tell me what is wrong with this code?
This looks like code from K&R
The C Programming Language, 2nd Edn (1988), Chapter 1, p18.
The problem is that your transcription of the code is misinterpreting %ld as %1d. Given that nc is of type long, you need %ld (letter ell) and not %1d (digit one). The book contains an ell and not a one.
With suitable options, compilers like GCC and Clang will give warnings about type mismatches in the format strings. Use -Wall -Werror to get errors when the code is malformed (or -Wformat if you can't work with -Wall — but I use -Wall -Wextra -Werror plus a few extra fussier options for all my compilations; I won't risk making mistakes that the compiler can tell me about).
The use of main() shows that the book is dated. C99 requires a return type and prefers void in the argument list — int main(void) — when you don't make use of the command line arguments.
As to the program not finishing, when you're typing at the terminal, you indicate EOF (end of file) to the program by typing Control-D on most Unix-like systems (though it is configurable), and Control-Z on Windows systems. (If you want to indicate EOF without typing a newline immediately beforehand, you need to type the EOF indicator twice instead of just once.) Or you can feed it a file from the shell: counter < data-file (assuming the program is called counter and you want to count the characters in the file data-file).
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
#include <stdio.h>
main()
{
double nc;
for(nc=0; getchar()!=EOF; ++nc);
printf("%1d\n",nc);
}
This is my first time learning C, and there are a few things I don't seem to understand too well. The for loop has a rather simple structure the only constraint being if getchar does not equal EOF (whatever that value EOF is set to be). Every time getchar does NOT equal EOF, nc gets incremented. Finally we get out of the for loop with nc being adjusted to the length of the string.
However the program is only taking inputs and not displaying the value that should be associated with the length of the character.
What am I not understanding? I'm assuming the book has a much higher chance in being right than me so I guess I'm going wrong somewhere.
The program keeps reading input until it comes to the end of the input. If you're typing on a terminal, you need to find out how to signal the end of the input. On Windows, press Ctrl+Z then Enter. On Unix-like systems (Linux, macOS, etc.), press Ctrl+D at the beginning of a line. Alternatively, make the program read from a file: on a Windows command line, run myprogram.exe <somefile.txt. On a Unix-like command line, run ./myprogram <somefile.txt.
Once the program does reach the end of the file, it'll likely crash or print a nonsensical value, because there's an error in your printf statement. nc is a floating-point value, but %d requires an integer value (more precisely, a value of type int). Here are three combinations that work:
Integer:
int nc;
…
printf("%d\n", nc);
Larger-size integer, like in the first example in K&R — note that it's a lowercase l, not a digit 1:
long nc;
…
printf("%ld\n", nc);
Floating-point number, which may allow larger values (on a modern PC, it allows larger values than long in a 32-bit program, but long allows larger values in a 64-bit program):
double nc;
…
printf("%f\n", nc);
A good compiler would warn you about the mismatch with printf. Make sure that you've enabled warnings. For example, here's what gcc -Wall -O aliman.c has to say about your program:
aliman.c:3:1: warning: return type defaults to ‘int’ [-Wreturn-type]
main()
^
aliman.c: In function ‘main’:
aliman.c:9:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat=]
printf("%1d\n",nc);
^
aliman.c:13:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
The warning about the return type of main is because main() is an obsolete shortcut, in modern C you need to write int main(). (Make that int main(void) if you're pedantic.) The last warning says that there's no return statement — the main function must return a value (conventionally, it indicates whether the program succeeded or failed). Both topics will be covered in §1.7.
However the program is only taking inputs and not displaying the value
that should be associated with the length of the character. What am I
not understanding? I'm assuming the book has a much higher chance in
being right than me so I guess I'm going wrong somewhere.
The for loop ends only when the standard input signals EOF. This can be done with Ctrl+d on Linux in general. For other operating systems you'd need to find the pendant.
After the for loop ends, the number of characters read will be displayed on standard output.
Some remarks: nc should be an integer. The format string for the printf function suffices to be %d then.
Formatting the source code can help you understand easier. Note that the for loop does not contain the printf (as you might have been assuming).
#include <stdio.h>
main()
{
int nc;
for(nc=0; getchar()!=EOF; ++nc)
;
printf("%d\n",nc);
}
You have three possible options
Change double to int
Change "%d" in the printf() to "%lf"
Cast nc to int like this (int)nc;
It will count '\n' as well
or if you do not to count '\n'
for (int i = 0; i != EOF; !i ? nc = 0 : nc, i != '\n' && i ? nc++ : nc, i = getchar());
Some of the examples in K&R don't work in Code:Blocks when I type them exactly.
For example, this program:
#include <stdio.h>
main()
{
long nc;
nc = 0;
while (getchar() != EOF)
++nc;
printf("%ld\n", nc);
}
When I type this code and run it, the program either freezes or doesn't do anything when I press enter.
The program below does the same thing (count characters in a string) and it works.
#include <stdio.h>
int main()
{
char s[1000];
int i;
scanf("%s",s);
for(i=0; s[i]!='\0'; ++i);
printf("Length of string: %d",i);
return 0;
}
Am I missing something here? Has C been changed since K&R 2nd Edition or am I doing something wrong?
When you press enter, you send \n into the standard input stream(and flushes other data into the stdin,if any). This character(\n) is not the same as EOF. To send EOF, press following keys combinations:
CTRL Z and then Enter in Windows.
CTRL D in Unix/Linux/OSX
C has been changed since that book was written, but even still the code is not well-defined/valid C under any version of the standard.
If you compile using the current C standard (C11), or the previous (C99), a strictly conforming compiler (such as gcc -std=c11 -pedantic-errors) will give an error: main must return int. The old "implicit int" feature was removed in C99.
If you compile using the old C90 standard, the code invokes undefined behavior, because there is no return statement. This was allowed in C90 but it is not safe, it could cause program crashes etc. Invoking undefined behavior is always a bug, and therefore very bad practice.
(In C99, functions returning a value must have a return statement, with the exception of main(), where return can be safely omitted. So you could omit the return statement of main() if you compile as C99.)
Simply correct the code as you have already done, and it will compile in any version of the standard, without invoking undefined behavior.
So I've read this question and other related questions, and I know that it's a good idea to check the return value of scanf to avoid surprises.
But I have the following scanf in my code:
/*
* If we don't gobble newlines,
* then they'll be interpreted as commands.
* Gobble both \n and \r (because the input files use 0x0D).
*/
(void) scanf("%*[\n\r]");
As you can see, I'm casting the result of scanf to void, but GCC still warns under -ansi -pedantic -Wall -O3, as noted here.
Is there anything clean I can do to suppress this warning without compiler-specific directives—that is, in pure ANSI C90?
(By clean I mean no if (scanf(...)); or similar.)
GCC 4.4 does warn in this case, but 4.7 and 4.9 do not. This lines up with the claim in that GCC bug you linked that it was fixed in 4.5. So one option is to use a version of the compiler less than five years old.
If you're stuck with GCC 4.4 or older, you can do this:
int dummy = scanf("%*[\n\r]");
(void)dummy;
This should be a familiar pattern to many C or C++ programmers.
If for some reason you object to using two statements and don't want to create an ignore() function as suggested by #pm100, you could also do this:
abs(scanf("%*[\n\r]"));
I would much prefer the (void)dummy solution though.
Finally, you could avoid scanf() altogether and do something like this (untested, not 100% sure it does what you need):
int ch;
do {
ch = getchar();
} while (ch == '\r' || ch == '\n');
ch = ungetc(ch, stdin);
assert(ch != EOF);
Obviously you'd put that all in a nice little function with a descriptive name, which is probably a good idea with the scanf() solutions too.
I am (re-)learning programming and I started with C. My IDE (if I may say so) is cygwin (32Bit) and Visual-Studio 2010 both on Windows7.
I am always compiling the code I write with gcc (cygwin) as well as with the VS2010 compiler. I do so, I guess, because I think it is a good way of learning.
Anyway I just learned about fflush(stdin), i.e. flushing the stdin buffer. Seems a good functionality because else, using scanf appears to be a pain.
So I wrote the code below based on an example from my text book. It compiles both with gcc in cygwin as well as with VS2010. When I run the VS compiled program it works fine (s.below), when I run the gcc compiled program in cygwin the fflush(stdin) does not flush the stdin buffer (s.below).
I have read some threads about fflush(stdin) having an undefined behaviour in some cases. Whatever that may mean, I took it from the C for Linux Programming textbook. If fflush(stdin) is not a valid means to get rid of stuff in the stdin buffer, what other standard method is there?
Thanks a lot for any answers!
==Program run under Windows:
enter a long integer and a double
23.00 78.99
lint = 23
dt = 0.00
enter a five digits input
78493
u entered 78 and 493
==Program run in Cygwin:
enter a long integer and a double
23.00 78.99
lint = 23
dt = 0.00
enter a five digits input
u entered 78 and 2665720
==CODE====
long lint;
double dt;
int fp, sp;
char fn[50], ln[50];
/* using the l modifier to enter long integers and doubles */
puts ("enter a long integer and a double");
scanf("%ld %lf", &lint, &dt);
printf("lint = %d\ndt = %.2f\n", lint, dt);
fflush(stdin); /*DOES NOT WORK UNDER CYGWIN!?*/
/* use field width to split input */
puts("\nenter a five digits input");
scanf("%2d %3d", &fp, &sp);
printf("u entered %d and %d\n", fp, sp);
C11 at 7.21.5.2.2 says (emphasis mine):
If stream points to an output stream or an update stream in which the most recent
operation was not input, the fflush function causes any unwritten data for that stream
to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.
This means that you shouldn't call fflush on an input stream (unless you are writing code for a very specific operating system and library where the behavior is defined)
There is a good reason for it! You would normally think that fflush(stdin) would flush the line you have just entered, right? Well there's more to it. Imagine running your program like this:
$ ./program < input_file
In this case, all the file is theoretically already in the buffer of stdin. Therefore, flushing that buffer equals ending your input which is quite a useless operation. For such reasons, fflush cannot have a very sensible behavior on input streams and that's why it's undefined on them.
If you want to ignore the current line, there are better ways to do it. One example is the following:
void flush_line(FILE *fin)
{
int c;
do
{
c = fgetc(fin);
} while (c != '\n' && c != EOF);
}
This reads the input character by character and stops until either end-of-file, read error or end-of-line occurs.
In the standard, fflush() is not defined for input streams. In Microsoft's documentation it is explicitly defined.
The upshot is that while you can use it with Microsoft's C library with clearly defined behaviour, such behaviour is not portable.
If you want to use GCC and have this work, then you could use MinGW/GCC since that uses Microsoft's C runtime rather than glibc.
You should not fflush an input stream. The differences you observe came from the fact that the behaviour of this operations is undefined.
From what I understand, you are writing this program for Linux and believe it or not, fflush(stdin) only works under Windows. (That's at least what I got from my C book called C for dummies). The alternative for fflush(stdin) on Linux is fpurge(stdin). Try it out and see if it works for you.
I'm learning C with The C Programming Language (K&R).
Since I don't particularly want to bob back and forth between a text editor and running gcc, I've decided to use xcode as an IDE. So far, I've been able to follow the book's examples without a problem up until section 1.5.2.
When given the valid (?) program...
#include <stdio.h>
void main()
{
long nc;
nc = 0;
while (getchar() != EOF)
++nc;
printf("%ld\n", nc);
}
...I receive no final output telling me how many characters were in my input. I am entering my input via the xcode console window.
Upon some debugging, it looks like my program gets stuck in the while loop, and never encounters the EOF token. To accommodate for this, I've instead substituted a newline as the new condition, by replacing EOF with "\n", which also does nothing and gives me a int to pointer comparison warning.
What am I doing wrong here?
Will I be able to follow K&R using xcode?
Type ^D (control-d) to send an EOF.
If you want to break on a newline, you need to compare the return value of getchar to '\n', not "\n". The former is the actual char value of a newline; the latter is a pointer to a char with that value. If that doesn't make sense to you yet, don't worry, it will once you've read more.