I have a program where the user enters two inputs. Being that I can't control what the user enters, the user can go past the fixed size of the array. Since fgets() appends retains a newline to the end before the null character, in the event that a newline cannot fit when the user goes beyond the intended size, the null character truncates the input. Does the newline character when the user hits enter still exist in the input stream? If so, is this the reason why fgets()skips the second time because of the newline from the first input?
#include <stdio.h>
int main(){
char str[5];
fgets(str,5,stdin);
printf("Output:%s",str);
fgets(str,5,stdin);
printf("Output:%s",str);
return 0;
}
Example Input
ABCDE\n
Output
Output:ABCDOutput:E
After reading this SO answer fgets() isn't prompting user a second time
, the issue seems to be not flushing the input stream via fflush(stdin), but I've heard conflicting information saying as this leads to undefined behavior. My last question is, what would be the appropriate way to clear the input stream if it's the retained newline that's causing issues?
the user can go past the fixed size of the array. Since fgets() appends a newline to the end before the null character
No, it does not. It writes characters read from the input into the provided buffer, up to and including the first newline, or until the specified buffer size is exhausted (less one byte for the string terminator), or until an error occurs or the end of the stream is reached, whichever comes first. The newline is not invented by fgets(); it comes from the input.
, in the event that a newline cannot fit when the user goes beyond the intended size, the null character truncates the input. Does the newline character when the user hits enter still exist in the input stream?
All characters entered by the user and not copied into the buffer remain waiting to be read in the stream. That will include the newline, if the user entered one.
If so, is this the reason why fgets()skips the second time because of the newline from the first input?
fgets() does not skip, but it does pick up where the previous call left off transferring characters from input to the buffer. No characters are lost. That means that the second call returns part of the first input line if the first call did not return the whole thing. You need to account one way or another for the possibility that the input does not conform to your line-length expectations.
the issue seems to be not flushing the input stream via fflush(stdin),
No, it isn't. Flushing is for sending buffered output to the underlying output device. Flushing an input stream produces undefined behavior. In principle, that could manifest as a buffer dump, and a given implementation might even specify such behavior, but you don't want that because there may be more data buffered than you want to get rid of.
but I've heard conflicting information saying as this leads to undefined behavior. My last question is, what would be the appropriate way to clear the input stream if it's the retained newline that's causing issues?
You read from the input until you've read the newline. There are plenty of I/O functions to choose from to accomplish this. fgets() itself might prove convenient, since you're already using it:
char str[5];
if (fgets(str, 5, stdin)) {
printf("Output:%s", str);
// read and consume the tail of the line, if any (overwrites str)
while (!strchr(str, '\n') && fgets(str, 5, stdin)) { /* empty */ }
}
fgets() reads until
1) New-line
2) Buffer is full
3) End-of-file
4) Input error (rare)
This code reads and takes care of #3 & #4
#define N 5
char buf[N];
if (fgets(buf, sizeof buf, stdin) == NULL) {
// Handle EOF or Error
return EOF;
}
To distinguish if a '\n' is present ... (#2 from #1)
// look for a lack of \n
if (strchr(buf, '\n') == NULL) {
And if so, read until it is found or EOF.
int ch;
while ((ch = fgetc(stdin)) != '\n' && ch != EOF);
}
--
Do not use the following code. It can be exploited by reading a null character as the first character.
size_t len = strlen(buf);
if (buf[len - 1] != '\n') { // bad way to detect \n
Could use
if (len > 0 && buf[len - 1] != '\n') { // Good
Being that I can't control what the user enters...
No, you cannot.
the user can go past the fixed size of the array.
Right. This is always a concern. However, In general you'll want to arrange things so that this rarely happens.
For example, if you really want to limit the user to (say) a 4-character-long input string, let him type whatever he wants, then see how much he typed, and if it was more than your limit, print a nice error message or something. But I do not recommend calling fgets(str, 5, stdin) if you're expecting 4 characters of input plus a newline, because it's just way too hard to recover when (not if) the user types too much.
in the event that a newline cannot fit when the user goes beyond the intended size, the null character truncates the input. Does the newline character when the user hits enter still exist in the input stream?
Absolutely yes.
If so, is this the reason why fgets()skips the second time because of the newline from the first input?
Pretty much yes.
I recommend allocating a much bigger buffer, and then proceeding something like this:
char inpbuf[512);
if(fgets(inpbuf, sizeof(inpbuf), stdin) == NULL) {
fprintf(stderr, "end of file\n");
return;
}
char *p = strrchr(inpbuf, '\n');
if(p == NULL) {
fprintf(stderr, "looks like you typed *way* too much\n");
return;
}
*p = '\0'; /* erase the \n */
if(strlen(inpbuf) > 4) {
fprintf(stderr, "you typed too much (max 4)\n");
return;
}
strcpy(str, inpbuf);
printf("Output:%s", str);
One glitch with this code as written, though: if the user hits the end-of-file key (control-D on Unix/Linux) before hitting Return, you'll falsely get the "looks like you typed way too much" message.
If the string read by fgets doesn't end in a newline, you know it's still in the buffer. In that case, call getchar in a loop until you get a newline.
fgets(str,5,stdin);
printf("Output:%s",str);
if (strchr(str, '\n') == NULL) {
int c;
while ((c = getchar()) != EOF && c != '\n');
}
fgets(str,5,stdin);
printf("Output:%s",str);
Related
I'm trying to read a line from stdin but I don't know to properly handle the cases when input size is at least equal to the limit. Example code:
void myfun() {
char buf[5];
char somethingElse;
printf("\nInsert string (max 4 characters): ");
fgets (buf, 5, stdin);
...
printf("\nInsert char: ");
somethingElse = getchar();
}
Now, the user can do three things:
Input less than 4 characters (plus newline): in this case there's nothing left in stdin and the subsequent getchar() correctly waits for user input;
Input exactly 4 characters (plus newline): in this case there's a newline left in stdin and the subsequent getchar() reads it;
Input more than 4 characters (plus newline): in this case there's at least another character left in stdin and the subsequent getchar() reads it, leaving at least a newline in.
Cases 2 and 3 would require emptying stdin using something like while(getchar() != '\n'), whereas case 1 doesn't require any additional action. As I understand from reading answers to similar questions and c-faq, there's no standard/portable way to know whether the actual scenario is the one described in 1 or not.
Did I get it well? Or there actually is a portable way to do it? Or maybe a totally different approach?
The fgets function will store the newline in the buffer if there is room for it. So if the last character in the string is not a newline, you know you need to flush the buffer.
fgets (buf, 5, stdin);
if (strrchr(buf, '\n') == NULL) {
// flush buffer
int c;
while ((c = getchar()) != '\n') && (c != EOF));
}
If ones assumes that a null character '\0' is never read, then #dbush answer will work.
If a null character is read, then strrchr(buf, '\n') does not find any '\n' that may have been read.
Code could pre-set the buffer to see if a '\n' was read in the end.
buf[sizeof buf - 2] = '\n';
if (fgets (buf, sizeof buf, stdin)) {
if (strrchr(buf, '\n') == NULL) {
// incomplete line read. (the usual detection)
} else if (buf[sizeof buf - 2] != '\n') {
// incomplete line read with prior null character (see below note).
}
}
Yet the C standard does not specify that data past what was read in buf[] is unchanged, pre-filling the buffer with some pattern is not sufficient to detect if a null character '\0' was read.
is a portable way to do it?
The most portable way is to use repeated calls to fgetc() or the like instead of fgets().
maybe a totally different approach?
I recommend fgetc() or the common but not C standard getline()
Another alternative: Use scanf("%4[^\n]%n", buf, &n): It is very cumbersome, yet a portable way is possible. It keeps track of the number of characters read before the '\n' even if some are null characters.
int n = 0;
cnt = scanf("%4[^\n]%n", buf, &n); // Cumbersome to get that 4 here.
// Lots of TBD code now needed:
// Handle if cnt != 1 (\n to be read or EOF condition)
// Handle if n == sizeof buf - 1, (0 or more to read)
// Handle if n < sizeof buf - 1, (done, now get \n)
// A \n may still need to be consumed
// Handle EOF conditions
So in the following bit of code I'm reading an option from the user to then decide whether to perform a given action:
printf("Do you want to execute %s: ", exe);
char input = getchar();
if (input == 'y') {
return execute(exe);
} return 0;
The problem I'm having is that after the line char input = getchar() a character (I'm assuming an enter key or newline) gets stuck in stdin, and a future call to fgets() (reading from stdin) from my execute() function therefore eats up this stuck character and doesn't prompt the user for the required input.
Now I can define the following function to 'eat' any stray characters for me if called before calling execute()...
void iflush() {
int c;
while ((c = getchar()) != EOF && c != '\n') {
continue;
}
}
... and this solves the problem. But I'm left wondering why this is happening in the first place? Is there a more 'proper' way of getting a char from stdin without causing this stray character which then messes up my other methods? I'm very new to C and am keen to be sure I'm learning good habits.
It seems odd that I have to add a helper method, even if simple, to prevent errors in my program just from recording some user input. I've tried using fgetc() also but same problem.
I'm left wondering why this is happening in the first place?
It's because when you can characters with %c (or fgetc()), it doesn't ignore ay of the whitespaces in the input stream.
Some format specifiers, for example %d, ignore any whitespaces left in the input stream. So, it's not a problem. But %c doesn't ignore it.
Hence, you typically use those "eat" functions.
Think if you are scanning a whitespace character (such as space, newline, etc), how'd you able to scan it using scanf()?
Obviously, there are different and better ways such as using fgets().
I'm very new to C and am keen to be sure I'm learning good habits.
My suggestion is to avoid scanf() completely. Instead use fgets() to read a line and then you can parse that line using sscanf(). Please read: Why does everyone say not to use scanf? What should I use instead?
One thing to be aware about fgets() is if you input buffer has enough space, then it'll read the newline character as well,
which you would want to avoid in most user inputs. So, you need to check if the last character is a newline and then remove it.
You can achieve it using strcspn() function such as:
char line[256];
if (fgets(line, sizeof line, stdin) == NULL) {
/* handle failure */
}
line[strcspn(line, "\n")] = 0; /* remove the newline char if present */
If you are mainly interested in reading just one char, then an array 3 chars would be sufficient. Still using a larger buffer doesn't hurt:
char line[256];
char ch;
if (fgets(line, sizeof line, stdin) == NULL) {
/* handle failure */
}
if (sscanf(line, "%c", &ch) != 1) {
/* handle failure */
}
/* Now you can use 'ch' to check if it's 'y' */
I'm trying to read a line with scanf("%[^\n]"); right before it I'm reading an integer with "%d", was told to me that scanf doesn't erase the '\n' after reading, so I have to call fflush() to avoid it, but even doing that I still have the same problems, so here is my code:
scanf("%d", &n);
fflush(stdin);
lines = (char**)malloc(sizeof(char*)*n);
for(i = 0; i < n; i++){
lines[i] = (char*)malloc(sizeof(char)*1001);
}
for(i = 0;i < n;i++){
scanf("%[^\n]", linhes[i]);
}
I read an integer and then the scanf doesn't wait, it starts reading the input — doesn't matter what the integer value is, whether 5 or 10, the scanf reads all the strings to empty. Already tried with fgets and the result is almost the same, except that it reads some of the strings and skips others.
Let us look at this step by step:
"... read a line with scanf("%[^\n]");".
scanf("%[^\n]", buf) does not read a line. It almost does - sometimes. "%[^\n]" directs scanf() to read any number of non-'\n' char until one is encountered (that '\n' is then put back into stdin) or EOF occurs.
This approach has some problems:
If the first char is '\n', scanf() puts it back into stdin without changing buf in anyway! buf is left as is - perhaps uninitialized. scanf() then returns 0.
If at least one non-'\n' is read, it is saved into buf and more char until a '\n' occurs. A '\0' is appended to buf and the '\n' is put back into stdin and scanf() returns 1. This unlimited-ness can easily overfill buf. If no char was saved and EOF or input error occurs, scanf() returns EOF.
Always check the return value of scanf()/fgets(), etc. functions. If your code does not check it, the state of buf is unknown.
In any case, a '\n' is still usually left in stdin, thus the line was not fully read. This '\n' often is an issue for the next input function.
... scanf doesn't erase the '\n' after reading
Another common misconception. scanf() reads a '\n', or not, depending on the supplied format. Some formats consume '\n', others do not.
... call fflush() to avoid it
fflush(stdin) is well defined in some compilers but is not in the C standard. The usual problem is code wants to eliminate any remaining data in stdin. A common alternative, when the end of the line had not yet occurred, is to read and dispose until '\n' is found:
int ch; // Use int
while ((ch = fgetc(stdin)) != '\n' && ch != EOF);
I still have the same problems
The best solution, IMO, is to read a line of user input and then scan it.
char buf[sizeof lines[i]];
if (fgets(buf, sizeof buf, stdin) == NULL) return NoMoreInput();
// If desired, remove a _potential_ trailing \n
buf[strcspn(buf, "\n")] = 0;
strcpy(lines[i], buf);
I recommend that a buffer should be about 2x the size of expected input for typical code. Robust code, not this snippet, would detect if more of the line needs to be read. IMO, such excessively long lines are more often a sign of hackers and not legitimate use.
BLUEPIXY in the comment answered my question:
try "%[^\n]" change to " %[^\n]"
Short version
I want to get rid of excess user input from stdin but I understand fflush(stdin) is not recommended. I found this replacement:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
However, if there is no excess data to remove, this will remove the user's next input. How can I check if there is data to remove from stdin so I can choose whether or not to use this method of clearing the buffer?
Long version with explanation
I'm making a command-line tool in Obj-C/C.
I understand that declaring char str[SIZE] syntax allocates SIZE bytes of memory to str. I'd like to allocate as little memory as possible to each variable in order to avoid wasting memory.
However, if you use fgets(str,sizeof(str),stdin) and you enter more than SIZE bytes of input, fgets will take SIZE bytes of your input and store that in str, leaving all the other data in the buffer. If you call fgets again, the remaining data will be stored in the variable you pass as fgets's first variable and essentially skip the prompt completely. I don't want this to happen. A common solution is fflush(stdin).
Various internet resources (including SO) state that using fflush(stdin) is not a good idea because it is "undefined" when you pass an input stream as argument.
I found this replacement on CProgramming.com
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
However, the same source mentions that if there is no excess data in stdin to get rid of, it will do this with the user's next input, so the second time fgets is called it might not receive all the data.
How can I check if there is data in stdin so I can decide whether or not to clear it?
If you use fgets to read lines, and you're worried that you might not have read the whole line, remember that if fgets read the whole line the newline character should be the last character in the input buffer.
Example:
char smallBuffer[10];
while (fgets(smallBuffer, sizeof(smallBuffer), stdin) != NULL)
{
if (strlen(smallBuffer) > 0)
{
// Check if we got the whole line
if (smallBuffer[strlen(smallBuffer) - 1] == '\n')
{
// Yes, we got the whole line
}
else
{
// Whole line not read, there is still "excess" input
}
}
}
I was always bad at inputting characters in C and this is another example. Though I understood (maybe) what's happening but I can't figure out the solution.
I have the following code
scanf("%ld %ld",&n,&m);
for(i=0;i<n;i++)
scanf("%ld",&array[i]);
for(i=0;i<m;i++)
{
fflush(stdin);
//inputting a character 'R' but it is picking '\n' from past buffer
scanf("%c",&query);
//As a result of above problem, it is also acting wierd for same reason
scanf("%ld",&d);
printf("%c %ld",query,d);
printf("\nI=%ld\n",i);
}
Please help me figure out the reason why its happening and what is the solution.
Using scanf with %d (or %ld) only extracts the number from the input stream; it leaves the newline in the stream.
So when you write scanf("%c", it reads that newline.
To fix this (if your intent is that scanf("%c" reads the first character of the next line), you need to flush the input of the previous line. One way to do that is:
int ch; while ( (ch == getchar()) != EOF && ch != '\n' ) { }
Your line fflush(stdin); causes undefined behaviour - don't do that. The fflush function is only for output streams.
Also , it is a really good idea to check the return value of scanf. If it was not what you expected then you may wish to take some action, instead of pretending that a number was entered.
Since you are tired of input issues, I can give you a method that can help to simplify your live.
I can observe that:
You have problems in handling end-of-lines.
Sometimes you need to input numbers and sometimes you need characters or another kind of input. So, you (think that you) are forced to use formatted input.
My advice is that you separate the issue of reading input from the issue of interpreting data entered from input.
The standard C brings only a few functions to handle input/output operations, in the standard header <stdio.h>.
If you are not interested in very sofisticated I/O results, the standard library is enough.
However, the functions of <stdio.h> usually have the effect that input is read one line at the time, which includes the end-of-line character: '\n'.
What you can do, then, it's what follows:
Read a line with fgets(..., stdin) and put the result in a buffer (not so long), used only for this purpose.
Once you have read an entire line, no more issues with end-of-line will bother you.
Then, re-read this line, that it's held in a buffer, and apply to it all the formatted input that you need.
A short example:
#include <stdio.h>
int main(void) {
char buffer[200] = ""; // Initialize array to 0's
long int n, m;
char c;
fgets(buffer, sizeof(buffer), stdin);
sscanf(buffer,"%ld %ld",&n,&m);
// Now you have processed the "integer number" input,
// read input characters again, withou any "flushes" and extrange things:
fgets(buffer, sizeof(buffer), stdin);
sscanf(buffer,"%c", &c);
fgets(buffer, sizeof(buffer), stdin);
// and so on...
}
Thus, every time you need to separate a section of input from a previous one, just do a new line reading with fgets(..., stdin), which stores the input in buffer, and then process the buffer with sscanf(), which applies the format string to the buffer instead of the input itself (in its flesh).
Note: This method can have a little problem: If the string input has more than sizeof(buffer) characters (in the example: 200), the line is not completely read. This situation can be handled by checking if the character before last in buffer is not equal to '\n' nor '\0'. In such a case, you would make automatically some kind of "flushing input" operation (reading and discarding characters till the next end-of-line is found).