Related
This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 2 years ago.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void delspace(char *str);
int main() {
int i, loops;
char s1[101], s2[101];
scanf("%d", &loops);
while (loops--) {
fgets(s1, 101, stdin);
fgets(s2, 101, stdin);
s1[strlen(s1)] = '\0';
s2[strlen(s2)] = '\0';
if (s1[0] == '\n' && s2[0] == '\n') {
printf("YES\n");
continue;
}
delspace(s1);
delspace(s2);
for (i = 0; s1[i] != '\0'; i++)
s1[i] = tolower(s1[i]);
for (i = 0; s2[i] != '\0'; i++)
s2[i] = tolower(s2[i]);
if (strcmp(s1, s2) == 0) {
printf("YES\n");
}
else {
printf("NO\n");
}
}
return 0;
}
void delspace(char* str) {
int i = 0;
int j = 0;
char sTmp[strlen(str)];
while (str[i++] != '\0') {
if (str[i] != ' ') {
sTmp[j++] = str[i];
}
}
sTmp[j] = '\0';
strcpy(str, sTmp);
}
After I entered "loops", "s1" was assigned a blank line automatically. How does it happen? I'm sure my keyboard works fine.
scanf() reads exactly what you asked it to, leaving the following \n from the end of that line in the buffer where fgets() will read it. Either do something to consume the newline, or (my preferred solution) fgets() and then sscanf() from that string.
scanf leaves whitespace in the input buffer, including new-line characters. To use fgets to read the next line you need to manually remove the rest of the current line:
int c;
do{
c = getchar();
}while(c != EOF && c != '\n');
This is a more Simpler solution
scanf("%d",&loops);
while ((getchar()) != '\n'); //This will consume the '\n' char
//now you're free to use fgets
fgets(string,sizeof(string),stdin);
Geekosaur has answered your question well, I'm just pointing out another "problem" with your code.
The line s1[strlen(s1)] = '\0'; is a no-op if s1 is already properly null terminated BEFORE it executes.
But if s1 is NOT already properly null-terminated BEFORE this line executes (and you're unlucky) it will cause:
a SIGSEGV on a POSIX (*nix) system.
a GPF on Windows.
This is because strlen basicaly finds the index of the existing null-terminator and returns it! Here's a valid, unoptimized implementation of strlen:
int strlen(char *string) {
int i = 0;
while(string[i] != '\0') {
++i;
}
return i;
}
So... If you're REALLY worried about strings NOT being null-terminated then you'd do something like:
string[sizeof(string)]='\0'; on local automatic strings (where the compiler "knows" the size of the string);
or string[SIZE_OF_STRING] for all other strings, where SIZE_OF_STRING is (most commonly) a #define'd constant, or a variable which you maintain specifically to store the current-SIZE (not length) of a dynamically allocated string.
And if you're REALLY, REALLY, REALLY worried about strings not being null-terminated (like you're dealing with "dirty" libary methods (like Tuxedo's ATMI for example) you ALSO "clear" your "return strings" before passing them to the suspect library methods with:
before:memset(string, NULL, SIZE_OF_STRING);
invoke: DirtyFunction(/*out*/string);
after: string[SIZE_OF_STRING]='\0'
SIG11's are a complete biatch to find because (unless you "hook" them with a signal-processor and say otherwise, they cause Unix to hard-terminate your program, so you can't log anything (after the fact) to help figure out where-in-the-hell-did-that-come-from... especially considering that in many cases the line of code which throws the SIG11 is no-where-near the actual cause of the string loosing its null-terminator.
Does that make sense to you?
PS: WARNING: strncpy does NOT always null terminate... you probably meant strlcpy instead. I learned this the hard way... when a 60 million dollar billing run crashed.
EDIT:
FYI: Here's a "safe" (unoptimized) version of strlen which I'll call strnlen (I reckon this should be in string.h. Sigh.).
// retuns the length of the string (capped at size-1)
int strnlen(char *string, int size) {
int i = 0;
while( i<size && string[i]!='\0' ) {
++i;
}
return i;
}
just put
scanf("%d\n",&loops);
instead of
scanf("%d",&loops);
Another way to ignore following newline character (due to hitting ENTER) after scanning the integer in variable label loops is:
scanf ("%d%*c", &loops);
Where, as per the man pages:
* Suppresses assignment. The conversion that follows occurs as usual, but no pointer is used; the result of the conversion is simply discarded.
This is very unlikely, but good habit to check for error during scanf:
errno = 0
scanf ("%d%*c", &loops);
if (errno != 0) perror ("scanf");
// act accordingly to avoid un-necessary bug in the code
For example in your code, loops is a local un-initialized variable, containing garbage. If scanf fails to fill the desired value, following while loop may run arbitrarily.
scanf() leave the following \n from the end of that line in the buffer where fgets() will read it. To slove this we have to do something to consume the newline. Let's see the problem.
The problem
#include<stdio.h>
void main()
{
char input[10];
printf("Enter in fgets: ");
scanf("%s", input);
getchar();
printf("Enter in scanf: ");
fgets(input, 10, stdin);
}
Output:
Enter in scanf: Hello
Enter in fgets:
As you can see that it dons't show the fgets part. Let's see the solution.
Put getchar() between scanf and fgets()
#include<stdio.h>
void main()
{
char input[10];
printf("Enter in fgets: ");
scanf("%s", input);
getchar();
printf("Enter in scanf: ");
fgets(input, 10, stdin);
}
Output:
Enter in scanf: Hello
Enter in fgets: Hello
If it's possible use scanf() after the fgets()
#include<stdio.h>
void main()
{
char input[10];
printf("Enter in fgets: ");
fgets(input, 10, stdin);
getchar();
printf("Enter in scanf: ");
scanf("%s", input);
}
Output:
Enter in fgets: Hello
Enter in scanf: Hello
Put fget() 2 times(This method don't work some time)
#include<stdio.h>
void main()
{
char input[10];
printf("Enter in fgets: ");
scanf("%s", input);
getchar();
printf("Enter in scanf: ");
fgets(input, 10, stdin);
fgets(input, 10, stdin)
}
Output:
Enter in scanf: Hello
Enter in fgets: Hello
Put sscanf() inseted of scanf()
#include<stdio.h>
void main()
{
char input[10];
printf("Enter in fgets: ");
sscanf(hello, "%s", input);
getchar();
printf("Enter in scanf: ");
fgets(input, 10, stdin);
}
Output:
Enter in sscanf: Hello
Enter in fgets: Hello
This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 3 years ago.
In C:
I'm trying to get char from the user with scanf and when I run it the program don't wait for the user to type anything...
This is the code:
char ch;
printf("Enter one char");
scanf("%c", &ch);
printf("%c\n",ch);
Why is not working?
The %c conversion specifier won't automatically skip any leading whitespace, so if there's a stray newline in the input stream (from a previous entry, for example) the scanf call will consume it immediately.
One way around the problem is to put a blank space before the conversion specifier in the format string:
scanf(" %c", &c);
The blank in the format string tells scanf to skip leading whitespace, and the first non-whitespace character will be read with the %c conversion specifier.
First of all, avoid scanf(). Using it is not worth the pain.
See: Why does everyone say not to use scanf? What should I use instead?
Using a whitespace character in scanf() would ignore any number of whitespace characters left in the input stream, what if you need to read more inputs? Consider:
#include <stdio.h>
int main(void)
{
char ch1, ch2;
scanf("%c", &ch1); /* Leaves the newline in the input */
scanf(" %c", &ch2); /* The leading whitespace ensures it's the
previous newline is ignored */
printf("ch1: %c, ch2: %c\n", ch1, ch2);
/* All good so far */
char ch3;
scanf("%c", &ch3); /* Doesn't read input due to the same problem */
printf("ch3: %c\n", ch3);
return 0;
}
While the 3rd scanf() can be fixed in the same way using a leading whitespace, it's not always going to that simple as above.
Another major problem is, scanf() will not discard any input in the input stream if it doesn't match the format. For example, if you input abc for an int such as: scanf("%d", &int_var); then abc will have to read and discarded. Consider:
#include <stdio.h>
int main(void)
{
int i;
while(1) {
if (scanf("%d", &i) != 1) { /* Input "abc" */
printf("Invalid input. Try again\n");
} else {
break;
}
}
printf("Int read: %d\n", i);
return 0;
}
Another common problem is mixing scanf() and fgets(). Consider:
#include <stdio.h>
int main(void)
{
int age;
char name[256];
printf("Input your age:");
scanf("%d", &age); /* Input 10 */
printf("Input your full name [firstname lastname]");
fgets(name, sizeof name, stdin); /* Doesn't read! */
return 0;
}
The call to fgets() doesn't wait for input because the newline left by the previous scanf() call is read and fgets() terminates input reading when it encounters a newline.
There are many other similar problems associated with scanf(). That's why it's generally recommended to avoid it.
So, what's the alternative? Use fgets() function instead in the following fashion to read a single character:
#include <stdio.h>
int main(void)
{
char line[256];
char ch;
if (fgets(line, sizeof line, stdin) == NULL) {
printf("Input error.\n");
exit(1);
}
ch = line[0];
printf("Character read: %c\n", ch);
return 0;
}
One detail to be aware of when using fgets() will read in the newline character if there's enough room in the inut buffer. If it's not desirable then you can remove it:
char line[256];
if (fgets(line, sizeof line, stdin) == NULL) {
printf("Input error.\n");
exit(1);
}
line[strcpsn(line, "\n")] = 0; /* removes the trailing newline, if present */
This works for me try it out
int main(){
char c;
scanf(" %c",&c);
printf("%c",c);
return 0;
}
Here is a similiar thing that I would like to share,
while you're working on Visual Studio you could get an error like:
'scanf': function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS
To prevent this, you should write it in the following format
A single character may be read as follows:
char c;
scanf_s("%c", &c, 1);
When multiple characters for non-null terminated strings are read, integers are used as the width specification and the buffer size.
char c[4];
scanf_s("%4c", &c, _countof(c));
neither fgets nor getchar works to solve the problem.
the only workaround is keeping a space before %c while using scanf
scanf(" %c",ch); // will only work
In the follwing fgets also not work..
char line[256];
char ch;
int i;
printf("Enter a num : ");
scanf("%d",&i);
printf("Enter a char : ");
if (fgets(line, sizeof line, stdin) == NULL) {
printf("Input error.\n");
exit(1);
}
ch = line[0];
printf("Character read: %c\n", ch);
try using getchar(); instead
syntax:
void main() {
char ch;
ch = getchar();
}
Before the scanf put fflush(stdin); to clear buffer.
The only code that worked for me is:
scanf(" %c",&c);
I was having the same problem, and only with single characters. After an hour of random testing I can not report an issue yet. One would think that C would have by now a bullet-proof function to retrieve single characters from the keyboard, and not an array of possible hackarounds... Just saying...
Use string instead of char
like
char c[10];
scanf ("%s", c);
I belive it works nice.
Provides a space before %c conversion specifier so that compiler will ignore white spaces. The program may be written as below:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char ch;
printf("Enter one char");
scanf(" %c", &ch); /*Space is given before %c*/
printf("%c\n",ch);
return 0;
}
You have to use a valid variable. ch is not a valid variable for this program. Use char Aaa;
char aaa;
scanf("%c",&Aaa);
Tested and it works.
Here first gets() is not working. if I add one more gets() function then from the two last one goes to work. how can I fix it?
CODE
#include<stdio.h>
#include<string.h>
int main(void)
{
short int choice;
char number[15];
do{
printf("\n\nAnswer: ");
scanf("%hd",&choice);
printf("\n");
if(choice==1)
{
printf("Enter the decimal number: ");
gets(number);
}
else
{
printf("Wrong input!.");
system("pause");
system("cls");
}
}while(choice!=1);
return 0;
}
Because the when the user pressed the enter key to give you the input for the scanf call, the enter key added a newline in the input buffer. And the gets call read that newline as an empty line.
One way to solve it is to use fgets to read the first input too, and use sscanf to parse it to a number:
...
printf("\n\nAnswer: ");
char input[64];
fgets(input, sizeof(input), stdin);
sscanf(input, "%hd", &choice);
printf("\n");
...
This make sure that the newline after the input is read and skipped.
Another way is to read one character at a time in a loop after the scanf call, until you have read the newline:
scanf("%hd", &choice);
int ch;
while ((ch = fgetc(stdin)) != EOF && ch != '\n')
{
// Empty
}
And a third way is to simply ask the scanf call to read and ignore white-space after the input:
scanf("%hd ", &choice);
// ^
// |
// Note space here
All of these methods have both pros and cons. You can try them all and use the one that works for you.
You need to skip the whitespace (i.e. the newline) following the number in the input buffer. This can be done by modifying the scanf to:
scanf("%hd ",&choice);
And use fgets(), since gets() is prone to buffer overflows.
I have this C code:
#include "stdio.h"
main()
{
struct books
{
char name[100],author[100];
int year,copies;
}book1,book2;
printf("Enter details of first book\n");
gets(book1.name);
gets(book1.author);
scanf("%d%d",&book1.year,&book1.copies);
printf("Enter details for second book\n");
gets(book2.name);
gets(book2.author);
scanf("%d%d",&book2.year,&book2.copies);
printf("%s\n%s\n%d\n%d\n",book1.name,book1.author,book1.year,book1.copies);
printf("%s\n%s\n%d\n%d\n",book2.name,book2.author,book2.year,book2.copies);
}
What is happening here is that it only scans till the author name of the second book. After that it directly prints the output.
Here is my input:(The first two lines are the initial printf statements)
Enter details of first book
warning: this program uses gets(), which is unsafe.
the c programmign laguagne
dfadsda
3432
23
Enter details for second book
ruby on rails
mark hammers
After which it directly prints the output:
the c programmign laguagne
dfadsda
3432
23
ruby on rails
0
0
What is wrong here? Also we can see that the name of the second book is assinged to the author.
I'm using gcc as the compiler on Mac OS X ML.
Use fflush(stdin) before each input statement. This method will clear the input buffer.
After the modification your code will be-
#include "stdio.h"
int main()
{
struct books
{
char name[100],author[100];
int year,copies;
}book1,book2;
printf("Enter details of first book\n");
gets(book1.name);
fflush(stdin);
gets(book1.author);
fflush(stdin);
scanf("%d%d",&book1.year,&book1.copies);
fflush(stdin);
printf("Enter details for second book\n");
gets(book2.name);
fflush(stdin);
gets(book2.author);
fflush(stdin);
scanf("%d%d",&book2.year,&book2.copies);
printf("%s\n%s\n%d\n%d\n",book1.name,book1.author,book1.year,book1.copies);
printf("%s\n%s\n%d\n%d\n",book2.name,book2.author,book2.year,book2.copies);
return 0;
}
You can see the details about fflush() here.
UPDATED :
Here after the scanf() statement you need to flush the input buffer. The fflush() method is not useful here because it is defined only for output streams. You can consume the rest of a partially-read line with a single line code after each scanf() line, like -
while((c = getchar()) != '\n' && c != EOF);
Than your code will be:
#include "stdio.h"
int main()
{
struct books
{
char name[100],author[100];
int year,copies;
}book1,book2;
char c;
printf("Enter details of first book\n");
gets(book1.name);
gets(book1.author);
scanf("%d%d",&book1.year,&book1.copies);
while((c = getchar()) != '\n' && c != EOF);
printf("Enter details for second book\n");
gets(book2.name);
gets(book2.author);
scanf("%d%d",&book2.year,&book2.copies);
while((c = getchar()) != '\n' && c != EOF);
printf("%s\n%s\n%d\n%d\n",book1.name,book1.author,book1.year,book1.copies);
printf("%s\n%s\n%d\n%d\n",book2.name,book2.author,book2.year,book2.copies);
return 0;
}
OUTPUT :
Enter details of first book
warning: this program uses gets(), which is unsafe.
sadsadas
asa
12
34
Enter details for second book
zxczxc
sds
23
22
sadsadas
asa
12
34
zxczxc
sds
23
22
In your source code,
scanf("%d%d",&book1.year,&book1.copies);
does not read the "\n" after "23" because this just reads two integers.
One solution for this problem is to do gets() before reading the second book, like:
#include "stdio.h"
main()
{
struct books
{
char name[100],author[100];
int year,copies;
}book1,book2;
printf("Enter details of first book\n");
gets(book1.name);
gets(book1.author);
scanf(" %d %d",&book1.year,&book1.copies);
char a[100];
gets(a);
printf("Enter details for second book\n");
gets(book2.name);
gets(book2.author);
scanf(" %d %d",&book2.year,&book2.copies);
printf("%s\n%s\n%d\n%d\n",book1.name,book1.author,book1.year,book1.copies);
printf("%s\n%s\n%d\n%d\n",book2.name,book2.author,book2.year,book2.copies);
}
For this reason, reading integer using gets and using atoi after that is simpler method.
#include "stdio.h"
main()
{
struct books
{
char name[100],author[100];
int year,copies;
}book1,book2;
printf("Enter details of first book\n");
gets(book1.name);
gets(book1.author);
char buff[100];
gets(buff);
book1.year = atoi(buff);
gets(buff);
book1.copies = atoi(buff);
printf("Enter details for second book\n");
gets(book2.name);
gets(book2.author);
gets(buff);
book2.year = atoi(buff);
gets(buff);
book2.copies = atoi(buff);
printf("%s\n%s\n%d\n%d\n",book1.name,book1.author,book1.year,book1.copies);
printf("%s\n%s\n%d\n%d\n",book2.name,book2.author,book2.year,book2.copies);
}
Solution:
#include <stdio.h> /* Using fgets(), scanf(), printf() in this program */
#include <string.h> /* Using strlen() in this program */
int main()
{
struct books
{
char name[100],author[100];
int year,copies;
}book1,book2;
char c;
char read_new_line;
printf("Enter details of first book\n");
if (fgets(book1.name, sizeof(book1.name), stdin) == NULL)
{
fprintf(stderr, "error reading name of book 1\n");
return -1;
}
/* Strip out \n character added by fgets */
book1.name[strlen(book1.name) - 1] ='\0';
if (fgets(book1.author, sizeof(book1.author), stdin) == NULL)
{
fprintf(stderr, "error reading author of book 1\n");
return -1;
}
/* Strip out \n character added by fgets */
book1.author[strlen(book1.author) - 1] ='\0';
scanf("%d %d",&book1.year,&book1.copies);
/* Strip out \n character left out in input stream */
while ((read_new_line = getchar()) != EOF && read_new_line != '\n')
;
printf("Enter details for second book\n");
if (fgets(book2.name, sizeof(book2.name), stdin) == NULL)
{
fprintf(stderr, "error reading name of book 2\n");
return -1;
}
/* Strip out \n character added by fgets */
book2.name[strlen(book2.name) -1 ] = '\0';
if (fgets(book2.author, sizeof(book2.author), stdin) == NULL)
{
fprintf(stderr, "error reading author of book 2\n");
return -1;
}
/* Strip out \n character added by fgets */
book2.author[strlen(book2.author) - 1] ='\0';
scanf("%d %d",&book2.year,&book2.copies);
/* Strip out \n character left out in input stream */
while((c = getchar()) != '\n' && c != EOF)
;
printf("%s\n%s\n%d\n%d\n",book1.name,book1.author,book1.year,book1.copies);
printf("%s\n%s\n%d\n%d\n",book2.name,book2.author,book2.year,book2.copies);
return 0;
}
Observation on code posted in the question:
Lets try to understand why your code is not working:
After the call to scanf from below statement
scanf("%d%d",&book1.year,&book1.copies);
Your input is
3432\n
23\n
scanf reads in 3432 and stores in &book1.year, following \n gets left out in input
stream. Then, second %d discards leading whitespaces (whitespaces in this context includes spaces, tabs, new line, etc.) and reads in 23 and stores that in &book1.copies, following \n gets left out in input stream.
when gets(book2.name) is called \n left out in input stream matches gets() criteria and hence 'empty string' is assigned to book2.name and whatever is meant and user input provided for book2.name is stored in book2.author.
Followed by whatever string meant for book2.author and typed as user input is assigned to book2.year%d conversion is done to that and it fails, as no proper integer entered and scanf() returns failed.
Note :
Use of gets() is by itself real bad. As you use %s, you need to be sure to guard against buffer overflows, which you can't do with gets(). Read: Why does everyone say not to use gets()?
Some of the posted answers seems to suggest fflush() for clearing
stdin stream. Read, Why Shouldn't I use fflush(stdin)?
Just a small note, you should probably use fgets() instead of gets() since it's now deprecated due to buffer safety issues.
And it's due to the fact that scanf() will eat that last \n before it gets to read the data for the next entry.
try this instead
#include <stdio.h>
#include <string.h>
int main()
{
struct books
{
char name[100],author[100];
int year,copies;
}book1 = { 0 },book2 = { 0 }; // initialize to 0
printf("Enter details of first book\n");
printf( "name>" );
fgets(book1.name, sizeof(book1.name), stdin);
// remove \n
book1.name[strlen(book1.name)-1] = '\0';
printf( "author>");
fgets(book1.author, sizeof(book1.author), stdin);
book1.author[strlen(book1.author)-1] = '\0'; // remove \n
printf( "year copies>");
scanf("%d %d",&book1.year,&book1.copies);
fflush(stdin); // remove any garbage remaining like \n
printf("Enter details for second book\n");
printf( "name>" );
fgets(book2.name, sizeof(book2.name), stdin);
book2.name[strlen(book2.name)-1] = '\0';
printf( "author>");
fgets(book2.author, sizeof(book2.author), stdin);
book2.author[strlen(book2.author)-1] = '\0';
printf( "year copies>");
scanf("%d %d",&book2.year,&book2.copies);
printf("%s\n%s\n%d\n%d\n",
book1.name,book1.author,book1.year,book1.copies);
printf("%s\n%s\n%d\n%d\n",
book2.name,book2.author,book2.year,book2.copies);
return 0;
}
This question already has answers here:
Why doesn't getchar() wait for me to press enter after scanf()?
(10 answers)
Closed 3 years ago.
I'm trying to have the user enter in a number as many times as they want (and create a linked list node for each of the numbers).
However, I've tried multiple method of clearing the character input buffer but to no avail. Strangely, the code will execute once through but not execute correctly the second.
For example, with the code below, the terminal reads:
would you like to enter an integer?
y
Enter an integer: 4
would you like to enter an integer?
y
**program terminates**
And before when I was using scanf("%c", yesno); I would not even be able to input 'y' on the last line. It just terminated.
struct node *read_numbers(void){
struct node *first = NULL;
int n; char yesno;
yesno = 'y';
while( yesno == 'y'){
printf("Would you like enter an integer ((y) for yes/(n) for no):\n");
yesno = getchar();
while(getchar() != '\n');
if(yesno == 'y'){
printf("Enter an Integer:");
scanf(" %d", &n);
first = add_to_list(first, n);
} else {
return first;
}
} // end while
}
I read up on character inputs and buffers, and supposedly the getchar() method should work. Am I utilizing it wrong? I've also tried scanf() with extra spaces before and after the "%c", but to no avail.
You need to digest the newline after the scanf. You can do what you're doing above in the code:
scanf(" %d", &n);
while(getchar() != '\n');
first = add_to_list(first, n);
Can I recommend that you use fgets as a safer alternative to getchar and scanf?
As you've noticed these functions can buffer the newline and pass it on to the next function that reads from the standard input.
With fgets you can store the input in a char array and avoid such problems. Additionally, you can still check easily if the input consists of only a newline:
char user_input[10] = "";
printf("Would you like enter an integer ((y) for yes/(n) for no):\n");
/* get input or quit if only newline is entered, we only check the first char */
while(fgets(user_input, 3, stdin)[0] != '\n')
{
/* check if the first char is 'y', quicker to do than using strcmp */
if(user_input[0] == 'y')
{
int input = 0;
printf("Enter an Integer: ");
fgets(user_input, 5, stdin); /* get input again */
input = atoi(user_input); /* convert to int */
printf("Your integer is %d\n", input);
printf("Would you like to go again? y/n:\n");
}
else
{
return printf("No input there.\n");
}
}
getcharis get the data from stdin, while(getchar() != '\n'); just like clear the stdin buffer.
so the following code can work correctly