I was writing some code and used fgets to get user input. And then i wrote a loop over my code to keep asking for user input until the user prints quit. But the second time it asked, it wrote "Please enter your input" 2 times instead of 1 , and didn't wait for my input the first time.
So, i googled it and found that the stdin buffer was filled and it had to be cleared.
I found this solution :
void dump_line(FILE * fp) {
int ch;
while ((ch = fgetc(fp)) != EOF && ch != '\n') {
/* null body */;
}
}
and then calling from the main function :
dump_line(stdin);
I have a very hard time understanding it. As i understand it, it simply assigns "ch" the value of fgetc(stdin) .. I simply cant understand how would assigning fgetc(stdin) to "ch" clear the buffer .
Thank you very much for your help!
Here is an old snippet I am using for user input if I really need to do it in pure C:
int get_line(char *buffer, int bsize)
{
int ch, len;
fgets(buffer, bsize, stdin);
/* remove unwanted characters from the buffer */
buffer[strcspn(buffer, "\r\n")] = '\0';
len = strlen(buffer);
/* clean input buffer if needed */
if(len == bsize - 1)
while ((ch = getchar()) != '\n' && ch != EOF);
return len;
}
It retrieves bsize amount of letters from stdin and stores them into given buffer. stuff left in stdin input buffer will be cleaned automatically. It also removes newlines (\r and \n) from the input data.
Function returns the amount of characters sucessfully read.
it simply assigns "ch" the value of fgetc(stdin)
Calling fgetc has the side effect that a character is read and removed from that file stream.
Assigning fgetc(stdin) to ch is not what clears the buffer. It's the actual calling of fgetc(stdin) that does it. Each call (and thus, each iteration of the loop) eats a char from stdin.
How it works:
Call fgetc(stdin), and assign the result to ch.
If ch is not equal to either EOF or '\n', go to 1.
When the loop stops, one of two things will be true: Either you've just eaten the char that marks the end of the current line (read: you're at the next line now), or stdin is empty and you won't get any more input. (The latter is semi unusual in an interactive app, but common when people pipe stuff into your app from elsewhere. Be ready for it.)
fgetc() gets a character from the buffer. This code reads characters from the buffer until the end-of-file or a new-line is reached.
This is the same loop, but written differently, perhaps this will explain it:
void dump_line(FILE * fp) { /* dump a line from fp */
int ch; /* temporary storage for character */
while (1) {
ch = fgetc(fp); /* read char from fp, this removes it from the stream */
if (ch == EOF) /* break if we reached END-OF-FILE */
break;
if (ch == '\n') /* break if we reached a newline, because */
break; /* we have succesfully read a line */
}
}
Another example for clearing the buffer:
char ch[1];
while(1){
ch[0] = fgetc(stdin);
if(ch[0] == '\n' || ch[0] == EOF) break;
}
Here's a two line solution I came up with, hope this helps someone.
char ch;
while ((ch = fgetc(stdin)) == EOF || ch == '\n');
The fgetc both reads and removes from the STDIN buffer. It will continue to do so until it reaches the EOF or newline, meaning STDIN is now empty.
Related
I am facing some problems while understanding the following code.
It is a program to read Strings from keyboard if the length of the String is lesser than the specified size (i.e 'n' here).
If the length of a string is larger than the specified size, the remaining characters on the line will be discarded.
More specifically, I want to know what is happening inside the buffer and how getchar() is reading the data and not storing it in the buffer.
char * s_gets(char * st, int n)
{
char * ret_val;
int i = 0;
ret_val = fgets(st, n, stdin);
if (ret_val) // i.e., ret_val != NULL
{
while (st[i] != '\n' && st[i] != '\0')
i++;
if (st[i] == '\n')
st[i] = '\0';
else // must have words[i] == '\0'
while (getchar() != '\n')
continue;
}
return ret_val;
}
The code is slightly flawed, but does more or less the job outlined. It uses fgets() to do a lot of the work. That reads up to n - 1 characters from standard input. When it returns, there are a few possibilities:
(EOF) Nothing was available to be read. Nothing has been put in the buffer, but fgets() returned NULL.
(Normal) A line has been read and fitted into the buffer st. The buffer includes the newline.
(Overlong) Part of a line has been read, but the input did not find a newline.
(EOF without newline) Some data was read, but there wasn't a newline before EOF was detected.
Case 1 is simplest: the code returns NULL. Case 2 is handled by scanning the string that's read to find the newline. If the newline is found, it is overwritten with a null byte. Case 3 is handled at the same time; if the value found isn't a newline, it must be the null byte. The code drops into a loop that reads more characters until a newline is read. Case 4 is similar to case 3 in effect, but the code in the loop mishandles this — it doesn't detect and handle EOF, so the code would fall into an indefinite loop. That's a bug that needs to be fixed.
The getchar() loop doesn't assign anything to the buffer st — it makes no changes to st. That continues to contain a null terminated string as read by fgets(). The getchar() loop reads and discards any characters left on the line that was read that did not fit into the buffer.
The code should be:
char *s_gets(char *st, int n)
{
assert(n > 1 && st != NULL);
char *ret_val = fgets(st, n, stdin);
if (ret_val != NULL)
{
int i = 0;
while (st[i] != '\n' && st[i] != '\0')
i++;
if (st[i] == '\n')
st[i] = '\0';
else
{
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
}
}
return ret_val;
}
The return value of NULL or the original string is the same as fgets() uses, but it isn't the most useful return value. It would be more useful, most often, if the code returned the length of the string that it read, or returned EOF if it encountered EOF (or a read error). The information is readily available — in the variable i.
I was trying to take a full line input in C. Initially I did,
char line[100] // assume no line is longer than 100 letters.
scanf("%s", line);
Ignoring security flaws and buffer overflows, I knew this could never take more than a word input. I modified it again,
scanf("[^\n]", line);
This, of course, couldn't take more than a line of input. The following code, however was running into infinite loop,
while(fscanf(stdin, "%[^\n]", line) != EOF)
{
printf("%s\n", line);
}
This was because, the \n was never consumed, and would repeatedly stop at the same point and had the same value in line. So I rewrote the code as,
while(fscanf(stdin, "%[^\n]\n", line) != EOF)
{
printf("%s\n", line);
}
This code worked impeccably(or so I thought), for input from a file. But for input from stdin, this produced cryptic, weird, inarticulate behavior. Only after second line was input, the first line would print. I'm unable to understand what is really happening.
All I am doing is this. Note down the string until you encounter a \n, store it in line and then consume the \n from the input buffer. Now print this line and get ready for next line from the input. Or am I being misled?
At the time of posting this question however, I found a better alternative,
while(fscanf(stdin, "%[^\n]%*c", line) != EOF)
{
printf("%s\n", line);
}
This works flawlessly for all cases. But my question still remains. How come this code,
while(fscanf(stdin, "%[^\n]\n", line) != EOF)
{
printf("%s\n", line);
}
worked for inputs from file, but is causing issues for input from standard input?
Use fgets(). #FredK
char buf[N];
while (fgets(buf, sizeof buf, stdin)) {
// crop potential \n if desired.
buf[strcspn(buf, "\n")] = '\0';
...
}
There are to many issues trying to use scanf() for user input that render it prone to mis-use or code attacks.
// Leaves trailing \n in stdin
scanf("%[^\n]", line)
// Does nothing if line begins with \n. \n remains in stdin
// As return value not checked, use of line may be UB.
// If some text read, consumes \n and then all following whitespace: ' ' \n \t etc.
// Then does not return until a non-white-space is entered.
// As stdin is usually buffered, this implies 2 lines of user input.
// Fails to limit input.
scanf("%[^\n]\n", line)
// Does nothing if line begins with \n. \n remains in stdin
// Consumes 1 char after `line`, even if next character is not a \n
scanf("%99[^\n]%*c", line)
Check against EOF is usual the wrong check. #Weather Vane The following, when \n is first entered, returns 0 as line is not populated. As 0 != EOF, code goes on to use an uninitialized line leading to UB.
while(fscanf(stdin, "%[^\n]%*c", line) != EOF)
Consider entering "1234\n" to the following. Likely infinite loop as first fscanf() read "123", tosses the "4" and the next fscanf() call gets stuck on \n.
while(fscanf(stdin, "%3[^\n]%*c", line) != EOF)
When checking the results of *scanf(), check against what you want, not against one of the values you do not want. (But even the following has other troubles)
while(fscanf(stdin, "%[^\n]%*c", line) == 1)
About the closest scanf() to read a line:
char buf[100];
buf[0] = 0;
int cnt = scanf("%99[^\n]", buf);
if (cnt == EOF) Handle_EndOfFile();
// Consume \n if next stdin char is a \n
scanf("%*1[\n]");
// Use buf;
while(fscanf(stdin, "%[^\n]%*c", line) != EOF)
worked for inputs from file, but is causing issues for input from standard input?
Posting sample code and input/data file would be useful. With modest amount of code posted, some potential reasons.
line overrun is UB
Input begins with \n leading to UB
File or stdin not both opened in same mode. \r not translated in one.
Note: The following fails when a line is 100 characters. So meeting the assumption cal still lead to UB.
char line[100] // assume no line is longer than 100 letters.
scanf("%s", line);
Personally, I think fgets() is badly designed. When I read a line, I want to read it in whole regardless of its length (except filling up all RAM). fgets() can't do that in one go. If there is a long line, you have to manually run it multiple times until it reaches the newline. The glibc-specific getline() is more convenient in this regard. Here is a function that mimics GNU's getline():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long my_getline(char **buf, long *m_buf, FILE *fp)
{
long tot = 0, max = 0;
char *p;
if (*m_buf == 0) { // empty buffer; allocate
*m_buf = 16; // initial size; could be larger
*buf = (char*)malloc(*m_buf); // FIXME: check NULL
}
for (p = *buf, max = *m_buf;;) {
long l, old_m;
if (fgets(p, max, fp) == NULL)
return tot? tot : EOF; // reach end-of-file
for (l = 0; l < max; ++l)
if (p[l] == '\n') break;
if (l < max) { // a complete line
tot += l, p[l] = 0;
break;
}
old_m = *m_buf;
*m_buf <<= 1; // incomplete line; double the buffer
*buf = (char*)realloc(*buf, *m_buf); // check NULL
max = (*m_buf) - old_m;
p = (*buf) + old_m - 1; // point to the end of partial line
}
return tot;
}
int main(int argc, char *argv[])
{
long l, m_buf = 0;
char *buf = 0;
while ((l = my_getline(&buf, &m_buf, stdin)) != EOF)
puts(buf);
free(buf);
return 0;
}
I usually use my own readline() function. I wrote this my_getline() a moment ago. It has not been thoroughly tested. Please use with caution.
Looking to read in using scanf but I want to stop reading if I encounter a ',' '\0' (newline) or EOF
I'm not really sure how to stop achieve this.
I was using
char * aBuff;
char * bBuff;
char * cBuff;
//read in the first three lines and put them into char arrays
//while (scan() != (',' || '\0' || EOF)) //was trying to put it into a while loop, wasn't sure
scanf("%s", aBuff);
scanf("%s", bBuff);
scanf(%s, cBUff);
I plan on taking the input and putting them into separate arrays. Basically take input until a , or new line and place that data into an array and continue this process until the end of file.
scanf() is not a practical method to read until encountering ',', '\0', or EOF. Use fgetc().
The biggest problem is specifying '\0' in the format of scanf(). Example: with format "%[^,\0]", scanf() only reads "%[^," as it stops at the embedded '\0'. So with an invalid format specifier --> undefined behavior.
size_t ReadX(char *dest, size_t size) {
size_t len = 0;
if (size) {
while (--size > 0) {
int ch = fgetc(stdin);
if (ch == 0 || ch == ',' || ch == EOF) break; // maybe add \n too.
*dest[len++] = ch;
}
*dest[len] = '\0';
}
return len; // or maybe return the stopping ch
}
scanf() could be use if code used the ponderous:
scanf("%[\1\2\3...all_char_codes_min_char_to_max_char_except_,_and\0]%*c", &s);
You can try using scansets
scanf() should stop on EOF, but you'd want to maybe do something like this:
scanf("%[^,\0]", &s);
I have been thinking of ways to flush bad entries in scanf functions to allow for loop prompts to do their job.
I have a function call here that flushes the input. This works but it's still buggy if I enter something like 2q when I ask for an int.
void flushKeyBoard()
{
int ch; //variable to read data into
while((ch = getc(stdin)) != EOF && ch != '\n');
}
And then I'll have something like this in another function:
printf("Enter a value: ");
check = scanf("%f", &b);
while(check == 0)
{
printf("Invalid number entered. Please re-enter: ");
check = scanf("%f, &b");
flushKeyBoard();
}
Any better ideas? Someone suggested fflush(); but it's not really standard to use that here..
Using getchar (common, easily comprehensible)
int c;
while ((c = getchar()) != EOF && c != '\n'); /* <note the semicolon! */
if (c == EOF) {
if (feof(stdin)) {
/* Handle stdin EOF. */
}
else {
/* Handle stdin error. */
}
}
Using fgets (less common, less comprehensible)
char buf[8];
while (fgets(buf, sizeof buf, stdin) != NULL) {
size_t len = strlen(buf);
/*
* Exit the loop if either EOF was encountered before '\n', or
* if '\n' is detected.
*/
if (len + 1 != sizeof(buf) || memchr(buf, '\n', len))
break;
}
if (feof(stdin)) {
/* Handle stdin EOF. */
}
else {
/* Handle stdin error. */
}
Using a scanset with scanf (likely uncommon, easily comprehensible)
/*
* Combining the scanset with assignment suppression (the '*' before the
* scanset) will return EOF on EOF/error and 0 if '\n' was read.
*/
if (scanf("%*[^\n]") == EOF) {
if (feof(stdin)) {
// Handle stdin EOF.
}
else {
// Handle stdin error.
}
}
getchar(); // Flush the '\n'.
Using getline (likely uncommon, difficult)
char *buf = NULL;
size_t bufsize = 0;
ssize_t len;
/* getline() will stop reading on '\n' or EOF. */
len = getline(&buf, &bufsize, stdin);
/* No bytes read and EOF encountered, or there was an error. */
if (len == -1) {
if (feof(stdin)) {
/* Handle stdin EOF. */
}
else if (ferror(stdin)) {
/* Handle stdin error. */
}
else {
/* Handle errno error, if desired. */
}
/*
* The value of "buf" is indeterminate here, so you likely
* just want to return from the function/program at this point
* rather than continuing and potentially freeing an invalid
* buffer.
*/
}
free(buf);
Of course, all of these methods assume you want to handle things that happen on EOF/error differently than with \n, perhaps even all three being separate cases. For example, by placing one of the above snippets into a self-contained function, you might return 0 if \n was read or EOF on EOF/error, or even 0 on \n, EOF on EOF, and 1 on error.
Things worth noting:
The getchar and fgets methods are 100% cross-platform. I prefer the getchar method for its simplicity.
The scanset method is less cross-platform only because not all compilers implement scansets (and are therefore not C99-compliant).
The getline method is also not quite cross-platform: it's primarily implemented on GNU/Linux and on some other POSIX operating systems; this does not include Windows at this time. It isn't terribly difficult to write one yourself once you have some experience managing memory and working with pointers, but you'd be better off using one of the first two methods since writing an implementation of getline would likely end up using fgetc or fgets anyway (fgetc(stdin) and getchar() should behave identically).
You can use:
fscanf(stdin, "%*[^\n]%*c");
There's a few ways of doing this. Effectively, what you're trying to do is consume a line of text up to a \n character (or an EOF.) To do this properly, you should use sscanf (or fscanf.)
sscanf("%*[^\n]\n");
This uses the regular expression [^\n]*\n (Any number of characters that are NOT \n, followed by a \n) and consumes everything matching that.
Edit: Because I'm dumb and forgot that scanf regex's use a slightly different syntax.
If I do :
int main(){
const int LENGTH_LINE = 100;
char line[LENGTH_LINE];
int len;
FILE* fp = fopen(file.txt,"r");
fgets(line,LENGTH_LINE,fp);
len = strlen(line);
if(line[len-1] == '\n')
printf("I've a line");
//This work if the line have \n , but if the end line of the text dont have \n how can do it?
}
I need to know if I take a whole line with fgets because I got a delimiter.
According to http://en.cppreference.com/w/c/io/fgets
Reads at most count - 1 characters from the given file stream and stores them in str.
Parsing stops if end-of-file occurs or a newline character is found, in which case str will contain that newline character.
So, once fgets returns, there are 3 possibilities
LENGTH_LINE was reached
We got a newline
EOF was reached.
I'm assuming you have a line in cases 2 and 3.
In this case the detection condition is :
line[len-1] == '\n' || feof(fp)
Check for the newline character:
size_t len = 0;
// ... your code using fgets
len = strlen(line);
if ((len > 0) && (line[len - 1] == '\n'))
// your input contains the newline
After the fgets call, your line may not have a newline at the end if:
The character limit was reached before a newline was scanned - in your case this is LENGTH_LINE.
The end-of-file (EOF) was reached before a newline.
There was a read error, but in case of an error consider the contents of line unusable.
You should be looking at the return value from fgets so that you'll be able to handle the EOF: fgets returns NULL upon end-of-file or a read error. You can use feof to check for the end-of-file.
If you check feof, and know that you're at the end of your input with no fgets errors, then even without a newline character on the final line you'll know that you've read the entire line.
If for some reason you must have a newline character terminating each line, you can add it yourself:
// you've checked for EOF and know this is your final line:
len = strlen(line);
if (line[len-1] == '\n')
printf("I've a line");
else if ((len + 1) < LENGTH_LINE)
{
line[len] = '\n';
line[len + 1] = '\0';
}
else
// no room in your line buffer for an add'l character
Use like this
while(fgets(line,LENGTH_LINE,fp)!=EOF)
// your code here
Why not just use fgetc instead? That way you can just keep scanning until you get to the end of the line so you don't have to check if you have it.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char line[100];
int ch, i = 0;
FILE* fp = fopen(file.txt,"r");
while(ch != '\n' || ch != '\r' || ch != EOF) //or ch != delimiter
{
ch = fgetc(fp);
line[i] = ch;
i++;
}
line[i] = '\n';
line[i+1] = 0x00;
return 0;
}
In that example I just look for a new line, return, or EOF character but you can really make it look for anything you like (e.g. your delimiter). So if your delimiter was q you would just do
while(ch != 'q')...