Related
I have a confusion related to using puts(), gets(), putchar() and getchar() simultaneously use in the code.
When I have run the below code, it is doing all steps:
taking the input, printing the output, again taking the input, printing the output.
#include <stdio.h>
int main() {
char ch[34];
gets(ch);
puts(ch);
char g;
g = getchar();
putchar(g);
}
Output:
Priyanka
Priyanka
J
J
But, when I am using this code:
It is only doing two steps:
taking the input, printing the input, then one line space. I am not getting why it behaves like this.
Code:
#include <stdio.h>
int main() {
char g;
g = getchar();
putchar(g);
char ch[34];
gets(ch);
puts(ch);
getch();
}
Output:
P
P
There are some problems in the code and the input mechanisms are more complex than you infer:
you should not read input with gets(): this function cannot be used safely because it does not receive information about the destination array size so any sufficiently long input line will cause a buffer overflow. It has been removed from the C Standard. You should use fgets() instead and deal with the newline at the end of the buffer.
g should have type int to accommodate for all the values returned by getc(), namely all values of type unsigned char (in most current systems 0 to 255) and the special negative value EOF (usually -1).
Here is a modified version:
#include <stdio.h>
int main() {
char ch[34];
if (fgets(ch, sizeof ch, stdin))
fputs(ch, stdout);
int g = getchar();
if (g != EOF)
putchar(g);
return 0;
}
Output:
Priyanka
Priyanka
J
J
Regarding the behavior of the console in response to your program's input requests, it is implementation defined but usually involves 2 layers of buffering:
the FILE stream package implements a buffering scheme where data is read from or written to the system in chunks. This buffering can be controlled with setvbuf(). 3 settings are available: no buffering (which is the default for stderr), line buffered (usually the default for stdin and stdout when attached to a character device) and fully buffered with a customisable chunk size (common sizes are 512 and 4096).
when you call getchar() or more generally getc(stream), if a byte is available in the stream's buffer, it is returned and the stream position is incremented, otherwise a request is made to the system to fill the buffer.
if the stream is attached to a file, filling the buffer performs a read system call or equivalent, which succeeds unless at the end of file or upon a read error.
if the stream is attached to a character device, such as a terminal or a virtual tty like a terminal window on the graphics display, another layer of buffering gets involved where the device driver reads input from the input device and handles some keys in a special way such as Backspace to erase the previous character, cursor movement keys to move inside the input line, Ctrl-D (unix) or Ctrl-Z (windows) to signal the end of file. This layer of buffering can be controlled via the tcsetattr() system call or other system specific APIs. Interactive applications such as text editors typically disable this and retrieve raw input directly from the input device.
the keys typed by the user are handled by the terminal to form an input line, send back to the C stream API when the user types Enter (which is translated as a system specific end of line sequence), the stream functions perform another set of transformations (ie: converting CR/LF to '\n' on legacy systems) and the line of bytes is stored in the stream buffer. When getc() finally gets a chance to return the first available byte, the full line has already been typed and entered by the user and is pending in the stream or the device buffers.
In both programs, getchar() does not return the next byte read from stdin until a full line has been read from the terminal and stored in the stream buffer. In the first program, the rest of this line is ignored as the program exits, but in the second program, the rest of this line is available for the subsequent gets() to read. If you typed J and Enter, the line read is J\n and getchar() returns the 'J', leaving the newline [ending in the input stream, then gets() will read the newline and return an empty line.
Between the lines of the statements putchar() and gets() that I don't recommend using, discarding the input stream until EOF or till a newline occurs solves the problem:
.
.
int c;
while ((c = getchar()) != EOF && c != '\n')
;
.
.
I would recommend using fgets(3) which is quite safer to use, for example:
char str[1024];
if (fgets(str, sizeof str, stdin) == NULL) {
// Some problem, handle the error...
}
// or, Input is okay...
Well, you have a problem here. You use a function in your second sample code that is not part of the stdio package.
You call getch() which is not a stdio function. It is part of the ncurses library, and, if you don't specify on compilation that you will use it, then you cannot get an executable program. So this make me thing you are not telling all the truth.
Just taking the function getch() of of the program you get the full line
Priyanka
output, and the program terminated. I guess you used getch() to stop the output until you press a character. But as curses library requires you to call initscr() before calling any other curses library function, it is not correctly initialized, and the output you get can be wrong due to this.
I'll not repeat what others have already told you about the use of gets(), it is still in the standard library, and knowing what you do, you can still use it in properly controlled environments. Despite of that, the recommendation others have given to you is not applicable here, as you have not overflowed the short buffer you have used (of only 34 chars, too short, too easy to hang your program or to crash it)
The functions from stdio use a buffer, and the unix tty driver is also interferring here. Your terminal will not make available any character you input to the program until you press the <ENTER> key, then all those characters are read by the program into a buffer. They are consumed from the buffer, until it is empty, so it doesn't matter if you read them one by one (with fgetch(), or all at once (with fgets() ---i'll use this, more secure, function, from this point on) Everything just happens once you press the <ENTER> key.
fgetch() only takes one character, so if more than one are available, only one character is taken from the buffer, and the rest wait their turn. But fgets() reads all (and fills the buffer) until a \n is read (this is why gets() is so dangerous, because it doesn't know the size of your buffer /it doesn't have a parameter indicating the size of the buffer, as fgets() has/ and cannot control the read to stop before overflowing it)
So, in your case, as you press a series of characters, then hit return, the first sample reads the full string, and then the second getchar() takes the first of the second line (but you need to input two complete lines at that point) The second sample read the first char when you called getchar(), and the rest of the line when you called gets().
To read one character at a time, without waiting for a full line to be input, the terminal driver has to be programmed to read characters in raw mode. Cookied mode (the default) is used by unix to read complete lines, this allows you to edit, erase characters on the line, and only input it when you are ready and hit the <ENTER> key.
If you are interested in reading chars one by one from the terminal, read the manual page termios(4) which explains the interface and iocontrols to the tty device. The curses library does the necessary housekeeping to put the terminal in raw mode to allow programs like vi(1) to read the input char by char, but you need then not to use stdio directly, as its buffering system will eat the characters you try to get to eat with curses.
I have problems with my C program when I try to read / parse input.
Help?
This is a FAQ entry.
StackOverflow has many questions related to reading input in C, with answers usually focussed on the specific problem of that particular user without really painting the whole picture.
This is an attempt to cover a number of common mistakes comprehensively, so this specific family of questions can be answered simply by marking them as duplicates of this one:
Why does the last line print twice?
Why does my scanf("%d", ...) / scanf("%c", ...) fail?
Why does gets() crash?
...
The answer is marked as community wiki. Feel free to improve and (cautiously) extend.
The Beginner's C Input Primer
Text mode vs. Binary mode
Check fopen() for failure
Pitfalls
Check any functions you call for success
EOF, or "why does the last line print twice"
Do not use gets(), ever
Do not use fflush() on stdin or any other stream open for reading, ever
Do not use *scanf() for potentially malformed input
When *scanf() does not work as expected
Read, then parse
Read (part of) a line of input via fgets()
Parse the line in-memory
Clean Up
Text mode vs. Binary mode
A "binary mode" stream is read in exactly as it has been written. However, there might (or might not) be an implementation-defined number of null characters ('\0') appended at the end of the stream.
A "text mode" stream may do a number of transformations, including (but not limited to):
removal of spaces immediately before a line-end;
changing newlines ('\n') to something else on output (e.g. "\r\n" on Windows) and back to '\n' on input;
adding, altering, or deleting characters that are neither printing characters (isprint(c) is true), horizontal tabs, or new-lines.
It should be obvious that text and binary mode do not mix. Open text files in text mode, and binary files in binary mode.
Check fopen() for failure
The attempt to open a file may fail for various reasons -- lack of permissions, or file not found being the most common ones. In this case, fopen() will return a NULL pointer. Always check whether fopen returned a NULL pointer, before attempting to read or write to the file.
When fopen fails, it usually sets the global errno variable to indicate why it failed. (This is technically not a requirement of the C language, but both POSIX and Windows guarantee to do it.) errno is a code number which can be compared against constants in errno.h, but in simple programs, usually all you need to do is turn it into an error message and print that, using perror() or strerror(). The error message should also include the filename you passed to fopen; if you don't do that, you will be very confused when the problem is that the filename isn't what you thought it was.
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "usage: %s file\n", argv[0]);
return 1;
}
FILE *fp = fopen(argv[1], "r");
if (!fp) {
// alternatively, just `perror(argv[1])`
fprintf(stderr, "cannot open %s: %s\n", argv[1], strerror(errno));
return 1;
}
// read from fp here
fclose(fp);
return 0;
}
Pitfalls
Check any functions you call for success
This should be obvious. But do check the documentation of any function you call for their return value and error handling, and check for those conditions.
These are errors that are easy when you catch the condition early, but lead to lots of head-scratching if you do not.
EOF, or "why does the last line print twice"
The function feof() returns true if EOF has been reached. A misunderstanding of what "reaching" EOF actually means makes many beginners write something like this:
// BROKEN CODE
while (!feof(fp)) {
fgets(buffer, BUFFER_SIZE, fp);
printf("%s", buffer);
}
This makes the last line of the input print twice, because when the last line is read (up to the final newline, the last character in the input stream), EOF is not set.
EOF only gets set when you attempt to read past the last character!
So the code above loops once more, fgets() fails to read another line, sets EOF and leaves the contents of buffer untouched, which then gets printed again.
Instead, check whether fgets failed directly:
// GOOD CODE
while (fgets(buffer, BUFFER_SIZE, fp)) {
printf("%s", buffer);
}
Do not use gets(), ever
There is no way to use this function safely. Because of this, it has been removed from the language with the advent of C11.
Do not use fflush() on stdin or any other stream open for reading, ever
Many people expect fflush(stdin) to discard user input that has not yet been read. It does not do that. In plain ISO C, calling fflush() on an input stream has undefined behaviour. It does have well-defined behavior in POSIX and in MSVC, but neither of those make it discard user input that has not yet been read.
Usually, the right way to clear pending input is read and discard characters up to and including a newline, but not beyond:
int c;
do c = getchar(); while (c != EOF && c != '\n');
Do not use *scanf() for potentially malformed input
Many tutorials teach you to use *scanf() for reading any kind of input, because it is so versatile.
But the purpose of *scanf() is really to read bulk data that can be somewhat relied upon being in a predefined format. (Such as being written by another program.)
Even then *scanf() can trip the unobservant:
Using a format string that in some way can be influenced by the user is a gaping security hole.
If the input does not match the expected format, *scanf() immediately stops parsing, leaving any remaining arguments uninitialized.
It will tell you how many assignments it has successfully done -- which is why you should check its return code (see above) -- but not where exactly it stopped parsing the input, making graceful error recovery difficult.
It skips any leading whitespaces in the input, except when it does not ([, c, and n conversions). (See next paragraph.)
It has somewhat peculiar behaviour in some corner cases.
When *scanf() does not work as expected
A frequent problem with *scanf() is when there is an unread whitespace (' ', '\n', ...) in the input stream that the user did not account for.
Reading a number ("%d" et al.), or a string ("%s"), stops at any whitespace. And while most *scanf() conversion specifiers skip leading whitespace in the input, [, c and n do not. So the newline is still the first pending input character, making either %c and %[ fail to match.
You can skip over the newline in the input, by explicitly reading it e.g. via fgetc(), or by adding a whitespace to your *scanf() format string. (A single whitespace in the format string matches any number of whitespace in the input.)
Read, then parse
We just adviced against using *scanf() except when you really, positively, know what you are doing. So, what to use as a replacement?
Instead of reading and parsing the input in one go, as *scanf() attempts to do, separate the steps.
Read (part of) a line of input via fgets()
fgets() has a parameter for limiting its input to at most that many bytes, avoiding overflow of your buffer. If the input line did fit into your buffer completely, the last character in your buffer will be the newline ('\n'). If it did not all fit, you are looking at a partially-read line.
Parse the line in-memory
Especially useful for in-memory parsing are the strtol() and strtod() function families, which provide similar functionality to the *scanf() conversion specifiers d, i, u, o, x, a, e, f, and g.
But they also tell you exactly where they stopped parsing, and have meaningful handling of numbers too large for the target type.
Beyond those, C offers a wide range of string processing functions. Since you have the input in memory, and always know exactly how far you have parsed it already, you can walk back as many times you like trying to make sense of the input.
And if all else fails, you have the whole line available to print a helpful error message for the user.
Clean Up
Make sure you explicitly close any stream you have (successfully) opened. This flushes any as-yet unwritten buffers, and avoids resource leaks.
fclose(fp);
I have problems with my C program when I try to read / parse input.
Help?
This is a FAQ entry.
StackOverflow has many questions related to reading input in C, with answers usually focussed on the specific problem of that particular user without really painting the whole picture.
This is an attempt to cover a number of common mistakes comprehensively, so this specific family of questions can be answered simply by marking them as duplicates of this one:
Why does the last line print twice?
Why does my scanf("%d", ...) / scanf("%c", ...) fail?
Why does gets() crash?
...
The answer is marked as community wiki. Feel free to improve and (cautiously) extend.
The Beginner's C Input Primer
Text mode vs. Binary mode
Check fopen() for failure
Pitfalls
Check any functions you call for success
EOF, or "why does the last line print twice"
Do not use gets(), ever
Do not use fflush() on stdin or any other stream open for reading, ever
Do not use *scanf() for potentially malformed input
When *scanf() does not work as expected
Read, then parse
Read (part of) a line of input via fgets()
Parse the line in-memory
Clean Up
Text mode vs. Binary mode
A "binary mode" stream is read in exactly as it has been written. However, there might (or might not) be an implementation-defined number of null characters ('\0') appended at the end of the stream.
A "text mode" stream may do a number of transformations, including (but not limited to):
removal of spaces immediately before a line-end;
changing newlines ('\n') to something else on output (e.g. "\r\n" on Windows) and back to '\n' on input;
adding, altering, or deleting characters that are neither printing characters (isprint(c) is true), horizontal tabs, or new-lines.
It should be obvious that text and binary mode do not mix. Open text files in text mode, and binary files in binary mode.
Check fopen() for failure
The attempt to open a file may fail for various reasons -- lack of permissions, or file not found being the most common ones. In this case, fopen() will return a NULL pointer. Always check whether fopen returned a NULL pointer, before attempting to read or write to the file.
When fopen fails, it usually sets the global errno variable to indicate why it failed. (This is technically not a requirement of the C language, but both POSIX and Windows guarantee to do it.) errno is a code number which can be compared against constants in errno.h, but in simple programs, usually all you need to do is turn it into an error message and print that, using perror() or strerror(). The error message should also include the filename you passed to fopen; if you don't do that, you will be very confused when the problem is that the filename isn't what you thought it was.
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "usage: %s file\n", argv[0]);
return 1;
}
FILE *fp = fopen(argv[1], "r");
if (!fp) {
// alternatively, just `perror(argv[1])`
fprintf(stderr, "cannot open %s: %s\n", argv[1], strerror(errno));
return 1;
}
// read from fp here
fclose(fp);
return 0;
}
Pitfalls
Check any functions you call for success
This should be obvious. But do check the documentation of any function you call for their return value and error handling, and check for those conditions.
These are errors that are easy when you catch the condition early, but lead to lots of head-scratching if you do not.
EOF, or "why does the last line print twice"
The function feof() returns true if EOF has been reached. A misunderstanding of what "reaching" EOF actually means makes many beginners write something like this:
// BROKEN CODE
while (!feof(fp)) {
fgets(buffer, BUFFER_SIZE, fp);
printf("%s", buffer);
}
This makes the last line of the input print twice, because when the last line is read (up to the final newline, the last character in the input stream), EOF is not set.
EOF only gets set when you attempt to read past the last character!
So the code above loops once more, fgets() fails to read another line, sets EOF and leaves the contents of buffer untouched, which then gets printed again.
Instead, check whether fgets failed directly:
// GOOD CODE
while (fgets(buffer, BUFFER_SIZE, fp)) {
printf("%s", buffer);
}
Do not use gets(), ever
There is no way to use this function safely. Because of this, it has been removed from the language with the advent of C11.
Do not use fflush() on stdin or any other stream open for reading, ever
Many people expect fflush(stdin) to discard user input that has not yet been read. It does not do that. In plain ISO C, calling fflush() on an input stream has undefined behaviour. It does have well-defined behavior in POSIX and in MSVC, but neither of those make it discard user input that has not yet been read.
Usually, the right way to clear pending input is read and discard characters up to and including a newline, but not beyond:
int c;
do c = getchar(); while (c != EOF && c != '\n');
Do not use *scanf() for potentially malformed input
Many tutorials teach you to use *scanf() for reading any kind of input, because it is so versatile.
But the purpose of *scanf() is really to read bulk data that can be somewhat relied upon being in a predefined format. (Such as being written by another program.)
Even then *scanf() can trip the unobservant:
Using a format string that in some way can be influenced by the user is a gaping security hole.
If the input does not match the expected format, *scanf() immediately stops parsing, leaving any remaining arguments uninitialized.
It will tell you how many assignments it has successfully done -- which is why you should check its return code (see above) -- but not where exactly it stopped parsing the input, making graceful error recovery difficult.
It skips any leading whitespaces in the input, except when it does not ([, c, and n conversions). (See next paragraph.)
It has somewhat peculiar behaviour in some corner cases.
When *scanf() does not work as expected
A frequent problem with *scanf() is when there is an unread whitespace (' ', '\n', ...) in the input stream that the user did not account for.
Reading a number ("%d" et al.), or a string ("%s"), stops at any whitespace. And while most *scanf() conversion specifiers skip leading whitespace in the input, [, c and n do not. So the newline is still the first pending input character, making either %c and %[ fail to match.
You can skip over the newline in the input, by explicitly reading it e.g. via fgetc(), or by adding a whitespace to your *scanf() format string. (A single whitespace in the format string matches any number of whitespace in the input.)
Read, then parse
We just adviced against using *scanf() except when you really, positively, know what you are doing. So, what to use as a replacement?
Instead of reading and parsing the input in one go, as *scanf() attempts to do, separate the steps.
Read (part of) a line of input via fgets()
fgets() has a parameter for limiting its input to at most that many bytes, avoiding overflow of your buffer. If the input line did fit into your buffer completely, the last character in your buffer will be the newline ('\n'). If it did not all fit, you are looking at a partially-read line.
Parse the line in-memory
Especially useful for in-memory parsing are the strtol() and strtod() function families, which provide similar functionality to the *scanf() conversion specifiers d, i, u, o, x, a, e, f, and g.
But they also tell you exactly where they stopped parsing, and have meaningful handling of numbers too large for the target type.
Beyond those, C offers a wide range of string processing functions. Since you have the input in memory, and always know exactly how far you have parsed it already, you can walk back as many times you like trying to make sense of the input.
And if all else fails, you have the whole line available to print a helpful error message for the user.
Clean Up
Make sure you explicitly close any stream you have (successfully) opened. This flushes any as-yet unwritten buffers, and avoids resource leaks.
fclose(fp);
I have problems with my C program when I try to read / parse input.
Help?
This is a FAQ entry.
StackOverflow has many questions related to reading input in C, with answers usually focussed on the specific problem of that particular user without really painting the whole picture.
This is an attempt to cover a number of common mistakes comprehensively, so this specific family of questions can be answered simply by marking them as duplicates of this one:
Why does the last line print twice?
Why does my scanf("%d", ...) / scanf("%c", ...) fail?
Why does gets() crash?
...
The answer is marked as community wiki. Feel free to improve and (cautiously) extend.
The Beginner's C Input Primer
Text mode vs. Binary mode
Check fopen() for failure
Pitfalls
Check any functions you call for success
EOF, or "why does the last line print twice"
Do not use gets(), ever
Do not use fflush() on stdin or any other stream open for reading, ever
Do not use *scanf() for potentially malformed input
When *scanf() does not work as expected
Read, then parse
Read (part of) a line of input via fgets()
Parse the line in-memory
Clean Up
Text mode vs. Binary mode
A "binary mode" stream is read in exactly as it has been written. However, there might (or might not) be an implementation-defined number of null characters ('\0') appended at the end of the stream.
A "text mode" stream may do a number of transformations, including (but not limited to):
removal of spaces immediately before a line-end;
changing newlines ('\n') to something else on output (e.g. "\r\n" on Windows) and back to '\n' on input;
adding, altering, or deleting characters that are neither printing characters (isprint(c) is true), horizontal tabs, or new-lines.
It should be obvious that text and binary mode do not mix. Open text files in text mode, and binary files in binary mode.
Check fopen() for failure
The attempt to open a file may fail for various reasons -- lack of permissions, or file not found being the most common ones. In this case, fopen() will return a NULL pointer. Always check whether fopen returned a NULL pointer, before attempting to read or write to the file.
When fopen fails, it usually sets the global errno variable to indicate why it failed. (This is technically not a requirement of the C language, but both POSIX and Windows guarantee to do it.) errno is a code number which can be compared against constants in errno.h, but in simple programs, usually all you need to do is turn it into an error message and print that, using perror() or strerror(). The error message should also include the filename you passed to fopen; if you don't do that, you will be very confused when the problem is that the filename isn't what you thought it was.
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "usage: %s file\n", argv[0]);
return 1;
}
FILE *fp = fopen(argv[1], "r");
if (!fp) {
// alternatively, just `perror(argv[1])`
fprintf(stderr, "cannot open %s: %s\n", argv[1], strerror(errno));
return 1;
}
// read from fp here
fclose(fp);
return 0;
}
Pitfalls
Check any functions you call for success
This should be obvious. But do check the documentation of any function you call for their return value and error handling, and check for those conditions.
These are errors that are easy when you catch the condition early, but lead to lots of head-scratching if you do not.
EOF, or "why does the last line print twice"
The function feof() returns true if EOF has been reached. A misunderstanding of what "reaching" EOF actually means makes many beginners write something like this:
// BROKEN CODE
while (!feof(fp)) {
fgets(buffer, BUFFER_SIZE, fp);
printf("%s", buffer);
}
This makes the last line of the input print twice, because when the last line is read (up to the final newline, the last character in the input stream), EOF is not set.
EOF only gets set when you attempt to read past the last character!
So the code above loops once more, fgets() fails to read another line, sets EOF and leaves the contents of buffer untouched, which then gets printed again.
Instead, check whether fgets failed directly:
// GOOD CODE
while (fgets(buffer, BUFFER_SIZE, fp)) {
printf("%s", buffer);
}
Do not use gets(), ever
There is no way to use this function safely. Because of this, it has been removed from the language with the advent of C11.
Do not use fflush() on stdin or any other stream open for reading, ever
Many people expect fflush(stdin) to discard user input that has not yet been read. It does not do that. In plain ISO C, calling fflush() on an input stream has undefined behaviour. It does have well-defined behavior in POSIX and in MSVC, but neither of those make it discard user input that has not yet been read.
Usually, the right way to clear pending input is read and discard characters up to and including a newline, but not beyond:
int c;
do c = getchar(); while (c != EOF && c != '\n');
Do not use *scanf() for potentially malformed input
Many tutorials teach you to use *scanf() for reading any kind of input, because it is so versatile.
But the purpose of *scanf() is really to read bulk data that can be somewhat relied upon being in a predefined format. (Such as being written by another program.)
Even then *scanf() can trip the unobservant:
Using a format string that in some way can be influenced by the user is a gaping security hole.
If the input does not match the expected format, *scanf() immediately stops parsing, leaving any remaining arguments uninitialized.
It will tell you how many assignments it has successfully done -- which is why you should check its return code (see above) -- but not where exactly it stopped parsing the input, making graceful error recovery difficult.
It skips any leading whitespaces in the input, except when it does not ([, c, and n conversions). (See next paragraph.)
It has somewhat peculiar behaviour in some corner cases.
When *scanf() does not work as expected
A frequent problem with *scanf() is when there is an unread whitespace (' ', '\n', ...) in the input stream that the user did not account for.
Reading a number ("%d" et al.), or a string ("%s"), stops at any whitespace. And while most *scanf() conversion specifiers skip leading whitespace in the input, [, c and n do not. So the newline is still the first pending input character, making either %c and %[ fail to match.
You can skip over the newline in the input, by explicitly reading it e.g. via fgetc(), or by adding a whitespace to your *scanf() format string. (A single whitespace in the format string matches any number of whitespace in the input.)
Read, then parse
We just adviced against using *scanf() except when you really, positively, know what you are doing. So, what to use as a replacement?
Instead of reading and parsing the input in one go, as *scanf() attempts to do, separate the steps.
Read (part of) a line of input via fgets()
fgets() has a parameter for limiting its input to at most that many bytes, avoiding overflow of your buffer. If the input line did fit into your buffer completely, the last character in your buffer will be the newline ('\n'). If it did not all fit, you are looking at a partially-read line.
Parse the line in-memory
Especially useful for in-memory parsing are the strtol() and strtod() function families, which provide similar functionality to the *scanf() conversion specifiers d, i, u, o, x, a, e, f, and g.
But they also tell you exactly where they stopped parsing, and have meaningful handling of numbers too large for the target type.
Beyond those, C offers a wide range of string processing functions. Since you have the input in memory, and always know exactly how far you have parsed it already, you can walk back as many times you like trying to make sense of the input.
And if all else fails, you have the whole line available to print a helpful error message for the user.
Clean Up
Make sure you explicitly close any stream you have (successfully) opened. This flushes any as-yet unwritten buffers, and avoids resource leaks.
fclose(fp);
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
Why is my prof using two getchar(); at the end of our C program tutorials?
And what is the "better way" for this?
He is waiting for user input so that you can see the output to the program, otherwise it will just complete and the output will not be visible (depending on the OS). Take it out and give it a try.
He wants the console to stay open and wait for the user to press a key. I think to remember that depending on what happens in your professors program above the "getchar()". There might still be something in the buffer, so he added a second "getchar()". Not exactly the most elegant way to solve the problem.
Edit: Here is a little example. There is still a remaining "\n" in the buffer from the "scanf()" If you add a second "getchar()", you get the expected result. You have to flush the buffer before the "getchar()".
#include <stdio.h>
main()
{
int input;
scanf("%d", &input);
printf("The input is %d\n", input);
getchar();
return 0;
}
Edit 2: Here is a solution taken from here.
int c;
printf( "Press ENTER to continue... " );
fflush( stdout );
do c = getchar(); while ((c != '\n') && (c != EOF));
The best better way is not to add any code to try and keep the console window open: start your program right from the console window.
If you must start your program from the IDE and want the program to not terminate before the user presses Enter, one single getchar() should do it.
The second best better way to make the program terminate after the user presses a key, is to always make sure there are no inputs pending and use one single getchar().
The reason your teacher uses 2 getchar(), I guess, is that there is already a character in the input buffer from previous inputs. To consume all characters from the inputs, up to and including the ENTER, this is usual:
int ch;
/* ... */
printf("Press Enter"); fflush(stdout);
while ((ch = getchar()) != '\n' && ch != EOF) /* void */;
The reason a lot of beginners feel it necessary to put two getch calls in their code is that one single call often doesn’t work.
The reason for that is that getch fetches the next keyboard input from the input queue. Unfortunately, this queue gets filled whenever the user presses keys on the keyboard, even if the application isn’t waiting for input at that moment (of if it isn’t reading the whole input – see Lulu’s answer for an example). As a consequence, getch will fetch a character from the input queue without waiting for the next key press – which is really what the programmer wants.
Of course, this “solution” will still fail in a lot of cases, when there’s more than just one character in the keyboard queue. A better solution is to flush that queue and then request the next character. Unfortunately, there’s no platform-independent way to do this in C/C++ to my knowledge. The conventional way to do this in C++ (sorry, my C is limited) looks like this:
std::cin.ignore(std::cin.rdbuf()->in_avail());
This simply ignores all available input, effectively clearing the input queue. Unfortunately, this code doesn’t always work, either (for very arcane reasons).
Why is my prof using two getchar(); at the end of our C program tutorials?
Assuming you have something like
int main ( void )
{
int input;
scanf ( "%d", &input );
printf ( "The input is %d.\n", input );
getchar();
getchar();
return 0;
}
Two because scanf won't return until after an enter is pressed, but there will be the '\n' from the enter and any other characters you have entered in the input buffer.
So if you run the above and input 1234Enter, the program will pause after printing The input is 1234. until you then press Enter again. The first getchar reads the '\n' associated with the first Enter. If you input something else, such as 1234SpaceEnter, the program will not pause, as first getchar will read the space. Two getchars might not be enough, and you've interspersed the code for printing the response into the code for handling the input.
And what is the "better way" for this?
There are various standard ways of reading input in C. There are also platform specific ways of ignoring text in the input buffer, but you shouldn't need to do that if you use fgets to read a line of input instead of scanf to read some input from the last line entered.
fgets ( read input until '\n' or end of file ) followed by sscanf ( parse a string for input ) is safe from buffer overruns, and will absorb any extra input and line terminating '\n':
#include <stdio.h>
int main ( void )
{
int input;
char buf[16] = "";
fgets ( buf, sizeof buf, stdin );
sscanf ( buf, "%d", &input );
printf ( "The input is %d.\n", input );
fflush ( stdout );
getchar();
return 0;
}
Flushing stdout after the printf isn't normally needed for terminal IO, but can be if you're piping it to a disk ( typically when you're logging a crashing program it will lose the most interesting bit just before the crash if you don't flush ).
Because fgets reads up to and including the end of the line, there are no characters left in the buffer so you only need one getchar, and slightly awkward input such as 1234SpaceEnter doesn't cause the program to terminate without pausing.
However, most of the time you don't need to wait after running a console application - on Linux or other Unix systems you typically have a console open and run the program there, after which control returns to the shell. On Windows, IDEs such as Visual Studio typically run the program and pause it using something like:
"C:\WINDOWS\system32\cmd.exe" /c ""...\ConsoleApplication1.exe" & pause"
Or you can open cmd.exe and run it from there, or you can run it with a .pif shortcut and set the checkbox it not to close the console on exit, or you can create a batch file which runs it and pauses.
You really only need to make the program pause itself if you're on Windows and you're using a debugger to run it and you haven't set any breakpoints.
to pause the (probably) commandline program. he is using two, because using only one didn't work and he probably doesn't know why..
find him a better solution to do this (and not std::cin) and you'll be the hero of the day.
Probably to keep the output window open when you run the program from the IDE.
...why there are two there is beyond me though.
It is a naive solution to the unused buffered input problem. Your prof recognises the problem, but it seems does not know how to solve it properly.
If you use formatted input, only characters entered that match the format specifier are used. So if for example the last input requested a decimal integer using %d, you might enter at the console:
123<newline>
The formatted input will consume the "123", leaving the <newline> buffered. An unformatted input such as getchar() will consume that and return immediately. Since this is not what you want, your prof has used the "just add another getchar() kludge". This works only if the user enters the expected input. A hamfisted typist might type:
123w<newline>
Now the first getchar() gets the 'w', the second gets the <newline>, and your program terminates before you intended it to, and in a GUI environment, if the terminating process owns the window it is running in, then the OS closes it.
A more robust solution is to repeatedly call getchar() until the <newline> is found:
while( getchar() != '\n' ) { /*do nothing*/} ;
getchar() ; /* wait */
Of course if the previous input was a character, you need to check it was not already a <newline>:
while( ch != '\n' && getchar() != '\n' ) { /*do nothing*/} ;
getchar() ; /* wait */
Rather than putting the flush loop at the end just before the 'wait' input call, it is better to perform the buffer flush after every input that requires it. This is because that is where you know you need it, and how it should be coded. I tend to write wrapper functions for the input types I need.
getchar(); at the end of the program creates a "Press any key to continue" situation. I'm guessing that he likes hitting any key twice.
To fetch a remaining "\n" from the buffer so that the app closes.
Because one hit of the "enter" button generates two characters on Windows, see wikipedia. At least it used too, long time ago in a galaxy far far away ...