Why is gets() not consuming a full line of input? - c

I'm trying to use gets() to get a string from the user, but the program seems to be passing right over gets(). There is no pause for the user to give input. Why is gets() not doing anything?
char name[13];
printf("Profile name: ");
gets(name);
printf("\n%s", name);

Call getchar() before you call gets() or fgets(). Since gets() or fgets() is getting skipped due to an already present '\n' from previous inputs in stdin, calling getchar() would lead to itself getting skipped instead of gets() or fgets() or any other similar function. But remember its more of a hack and not a standard solution (I think so), and also use of gets() is forbidden.
printf("\nEnter a String: ");
getchar();
//fgets(inputString, 100, stdin);
gets(inputString);
printf("\n%s", inputString);

It's because gets() it's so incredibly dangerous to use, that some C libraries have removed it completely and replaced it with a version that does nothing.
Use fgets() instead.

Use fflush(stdin); before gets()

You get lot of troubles using gets()
Instead go for fgets()
fgets(name,13,stdin);
See this SO question Why is the gets function so dangerous that it should not be used?
The reason why fgets() does not work, may be you are not handling the newline left behind by scanf in your previous statements.
You can modify your scanf format string to take it into account:
scanf("%d *[^\n]", &N);
*[^\n] says to ignore everything after your integer input that isn't a newline, but don't do anything with the newline (skip it).
When you use scanf("%d",&num) you hit 13 and enter and 13 is stored in num and the newline character is still in the input buffer when you read fgets from stdin it treats \n as the data you have entered and the fgets() statement is skipped
You cannot flush input buffer however you can do this fseek(stdin,0,SEEK_END); add this before your every fgets statement

Take a look at gets() reference
Get string from stdin
Reads characters from the standard input (stdin) and stores them as a C string into str until a newline character or the end-of-file is reached.
The newline character, if found, is not copied into str.
A terminating null character is automatically appended after the characters copied to str.
Notice that gets is quite different from fgets: not only gets uses stdin as source, but it does not include the ending newline character in the resulting string and does not allow to specify a maximum size for str (which can lead to buffer overflows).
So, basically gets() is not only unsafe (can lead to buffer overflows) but also reads what's in the input buffer.
I recommend you to use fgets(), but if you want a quick (and lazy and stupid) solution, just flush the input buffer:
char name[13];
printf("Profile name: ");
fflush(stdin);
gets(name);
printf("\n%s", name);

Add this below function to your code and enjoy it.
string GetString()
{
char ch;
string Line="";
while(1)
{
ch=getchar();
if(ch=='\n')
break;
else
Line+=ch;
}
return Line;
}
This function can effect all Spaces and Backspaces too!!!

You might need to discard the rest of the line and move on to the beginning of the next one. You can do:
int c; while((c=getchar()) != '\n' && c != EOF);
This discards the rest of the current line (which might have been partially read with scanf(), etc.) and moves on to the next one.
Although fflush(stdin) might also discard the input, it is non-standard behaviour and discouraged.
You should never ever use gets(myString), as it has been completely removed from the C standard due to how unsafe it is. It doesn't enforce the length of the string, so you can go past the end of the buffer and overwrite other values in RAM, causing a buffer overflow, which can be a security vulnerability. Use fgets(myString, myStringSize, stdin); instead. To get rid of the newline in the resulting string, use myString[strcspn(myString, "\n")] = 0;.

Related

fgets() goes newline when storing string but gets() no issue about newline

fseek(fPtr, 0, SEEK_END);
fflush(stdin);
printf("\n\t\t\t ENTERID : ");
fgets(user.id, ID_SIZE, stdin);
fflush(stdin);
printf("tENTER FIRST NAME: ");
fgets(user.fname, MAX_FNAME_SIZE, stdin); //automatic added newline
printf("ENTER LAST NAME: ");
fgets(user.lname, MAX_LNAME_SIZE, stdin); //automatic added newline
I was using fgets() for reading the input of the string and store into the text file using the fwrite.
But why does fgets() automatically enter a newline for each input of string.
"...but gets() no issue about newline"
Note, that although your observation about gets() being preferable in this case over fgets() for handling newline, the unfavorable behaviors that come with gets() make it dangerous to use, with the result that "it was officially removed by the 2011 standard." (credit) Even without the \n mitigations mentioned below, fgets() is highly preferred over gets().
"fgets() goes newline when storing string..." and "...why does fgets() automatically enter a newline for each input of string"
fgets() does not enter the newline upon reading the line, rather if one exists, the newline is picked up as part of the line when fgets() called. For example in this case, when using stdin as the input method, the user clicks the <return> to finish inputting text. Upon hitting the <return> key, a \n is entered just like any other character, and becomes the last character entered. When the line is read using fgets(), if the \n is seen before any of its other stop reading criteria, fgets() stops reading, and stores all characters, including \n, terminates line with \0 and stores into the buffer. (If sizeof(buffer) - 1 or EOF is seen first, fgets() will never see the newline.)
To easily eliminate the \n, (or other typical unwanted line endings), use the following single line statements after each of your calls to fgets():
fgets(user.id, ID_SIZE, stdin);
user.id[strcspn(user.id, "\n")] = 0;
//fflush(stdin);//UB, should not be called
...
fgets(user.fname, MAX_FNAME_SIZE, stdin);
user.fname[strcspn(user.fname, "\n")] = 0;
...
fgets(user.lname, MAX_LNAME_SIZE, stdin);
user.lname[strcspn(user.lname, "\n")] = 0;
...
This technique works for truncating any string by searching for the unwanted char, whether it be "\n", "\n\r", "\r\n", etc. When using more than one search character, eg "\r\n", it searches until it reaches either the \r or the \n and terminates at that position.
"This [method] handles the rare buffer than begins with '\0', something that causes grief for the buffer[strlen(buffer) - 1] = '\0'; [method]." (#Chux - comment section of link below.)
Credit here
Quoting from the man page,
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte ('\0') is stored after the last character in the buffer.
So, after providing the input from the terminal, you press the ENTER key which adds a newline to the input buffer. That same newline is scanned and stored in the destination provided to fgets().
If you want to remove the trailing newline, use the solution mentioned in the answer: Removing trailing newline character from fgets() input
That said, read:
Why is the gets function so dangerous that it should not be used?
How is the working of fflush(stdin) changing the output in below code?

How can I fix the problem with gets() function in C?

There is a problem with gets function. The first gets I write does not work but the ones comes next works properly.
I put an extra gets() function at the beginning, program just skips it and gets the string I want. But it is not safe and reliable. So what is the problem with gets and how can I fix it?
if (choice == 1) {
printf("Please enter an English phrase with upper case: ");
gets(a);
gets(engphr);
for (i = 0; engphr[i] != '\0'; i++) {
As Eraklon mentions in their comment, the most likely cause is that you have a scanf call before the gets call, and the trailing newline from the previous input is getting consumed by gets before you have a chance to enter anything else.
You should never use gets anyway - it was removed from the standard library in the 2011 version of the language. It is inherently unsafe to use, and will introduce a security hole in your code. Use fgets instead. Its behavior is slightly different (it will save the trailing newline to the input buffer if there's room, where gets discarded it), but it's much safer:
if ( fgets( engphr, sizeof engphr, stdin ) ) // assumes engphr is declared as an array, not a pointer
{
// process engphr
}
Having said that, you really shouldn't mix calls to scanf and fgets, again because scanf will leave trailing newlines in the input stream from previous inputs, and fgets will immediately return after seeing that newline. Either read all input using fgets and use sscanf to read specific items from the input buffer, or read all input with scanf.

C: error replacing gets() with fgets()

I am currently having an issue replacing gets() with fgets(). I have looked at multiple examples of doing this and it seems very straight forward however I am getting unexpected output in doing so. Using the gets() method in comments below, I get good behavior from my shell program I am writing, however when I change to the fgets() call, I get output ": no such file or directory" when giving input "ls". Like I said, with the gets() call it is working fine. code below:
int main(void) {
while(1) {
int i = 0;
printf("$shell: ");
scanf("%s", first);
/* gets(input);*/
fgets(input, sizeof(input), stdin);
//...parse input into tokens for exec system call...
execvp(first, args);
}
return 0;
}
Unlike gets, fgets will read the newline and store it in the string.
From the man page:
fgets() reads in at most one less than size characters from stream
and stores them into the buffer pointed to by s. Reading stops
after an EOF or a newline. If a newline is read, it is stored into
the buffer. A '\0' is stored after the last character in the
buffer.
You can remove the newline (if it is present) by replacing it will a null byte:
fgets(input, sizeof(input), stdin);
if (input[strlen(input)-1] == '\n') input[strlen(input)-1] = '\0';

What are options scanf vs gets vs fgets?

I heve a following code
while ( a != 5)
scanf("%s", buffer);
This works well but takes no space in between the mentioned words or in other words, scanf terminates if we use spaces to scan
If I use this
while( a != 5)
scanf("%[^\n]", buffer);
It works only for once which is bad
I never use gets() because I know how much nasty it is..
My last option is this
while( a != 5)
fgets(buffer, sizeof(buffer), stdin);
So my questions are
Why the second command is not working inside the loop?
What are the other options I have to scan a string with spaces?
"%[^\n]" will attempt to scan everything until a newline. The next character in the input would be the \n so you should skip over it to get to the next line.
Try: "%[^\n]%*c", the %*c will discard the next character, which is the newline char.
Why the second command is not working inside the loop
Becuase, for the first time what you scan until \n, the \n is remaining in the input buffer. You need to eat up (or, in other word, discard) the stored newline from the buffer. You can make use of while (getchar()!=\n); to get that job done.
What are the other options I have to scan a string with spaces?
Well, you're almost there. You need to use fgets(). Using this, you can
Be safe from buffer overrun (Overcome limitation of gets())
Input strings with spaces (Overcome limitation of %s)
However, please keep in mind, fgets() reads and stores the trailing newline, so you may want to get rid of it and you have to do that yourself, manually.

how to read scanf with spaces

I'm having a weird problem
i'm trying to read a string from a console with scanf()
like this
scanf("%[^\n]",string1);
but it doesnt read anything. it just skips the entire scanf.
I'm trying it in gcc compiler
Trying to use scanf to read strings with spaces can bring unnecessary problems of buffer overflow and stray newlines staying in the input buffer to be read later. gets() is often suggested as a solution to this, however,
From the manpage:
Never use gets(). Because it is
impossible to tell without knowing the
data in advance how many characters
gets() will read, and because gets()
will continue to store characters past
the end of the buffer, it is extremely
dangerous to use. It has been used to
break computer security. Use fgets()
instead.
So instead of using gets, use fgets with the STDIN stream to read strings from the keyboard
That should work fine, so something else is going wrong. As hobbs suggests, you might have a newline on the input, in which case this won't match anything. It also won't consume a newline, so if you do this in a loop, the first call will get up to the newline and then the next call will get nothing. If you want to read the newline, you need another call, or use a space in the format string to skip whitespace. Its also a good idea to check the return value of scanf to see if it actually matched any format specifiers.
Also, you probably want to specify a maximum length in order to avoid overflowing the buffer. So you want something like:
char buffer[100];
if (scanf(" %99[^\n]", buffer) == 1) {
/* read something into buffer */
This will skip (ignore) any blank lines and whitespace on the beginning of a line and read up to 99 characters of input up to and not including a newline. Trailing or embedded whitespace will not be skipped, only leading whitespace.
I'll bet your scanf call is inside a loop. I'll bet it works the first time you call it. I'll bet it only fails on the second and later times.
The first time, it will read until it reaches a newline character. The newline character will remain unread. (Odds are that the library internally does read it and calls ungetc to unread it, but that doesn't matter, because from your program's point of view the newline is unread.)
The second time, it will read until it reaches a newline character. That newline character is still waiting at the front of the line and scanf will read all 0 of the characters that are waiting ahead of it.
The third time ... the same.
You probably want this:
if (scanf("%99[^\n]%*c", buffer) == 1) {
Edit: I accidentally copied and pasted from another answer instead of from the question, before inserting the %*c as intended. This resulting line of code will behave strangely if you have a line of input longer than 100 bytes, because the %*c will eat an ordinary byte instead of the newline.
However, notice how dangerous it would be to do this:
scanf("%[^n]%*c", string1);
because there, if you have a line of input longer than your buffer, the input will walk all over your other variables and stack and everything. This is called buffer overflow (even if the overflow goes onto the stack).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *text(int n);
int main()
{
char str[10];
printf("enter username : ");
scanf(text(9),str);
printf("username = %s",str);
return 0;
}
char *text(int n)
{
fflush(stdin);fflush(stdout);
char str[50]="%",buf[50],st2[10]="[^\n]s";
char *s;itoa(n,buf,10);
// n == -1 no buffer protection
if(n != -1) strcat(str,buf);
strcat(str,st2);s=strdup(str);
fflush(stdin);fflush(stdout);
return s;
}

Resources