Using scanf to read a string then a integer, reads string only - c

I'm trying to use two scanf's to read a string and then an integer. The program waits for me to enter the string, i press enter and then doesn't wait for me to insert the integer. The code i'm using:
printf("Insert the name of the author to search: ");
scanf("%300s", author);
printf("Insert the year: ");
scanf("%d", &year);
Any suggestions?

The conversion specifier "%s" breaks on whitespace.
If you enter, for instance, "John Smith", the variable author will have "John" and the rest of the input will be used for year.
Always validate the return value of (most) library functions.
printf("Insert the name of the author to search: ");
if (scanf("%300s", author) != 1) /* error */;
printf("Insert the year: ");
if (scanf("%d", &year) != 1) /* error */;
The best way to get user input is to use fgets(), then, if needed, parse the input and assign to variables.
char tmp[1000];
printf("Insert the name of the author to search: ");
if (!fgets(tmp, sizeof tmp, stdin)) /* error */;
strcpy(author, tmp);
printf("Insert the year: ");
if (!fgets(tmp, sizeof tmp, stdin)) /* error */;
if (sscanf(tmp, "%d", &year) != 1) /* error */;

you are trying to read input into author array where input length can be upto 300 characters,So i hope that you have declared your array size aschar author[301] , 300+1 (one extra for accomadating '\0').
You can use function like this scanf(" %300[^\n],author") this means keep reading characters from keyboard(or you can say keyboard buffer) until '\n' is found, and '\n' is generated when you hit Enter key,Hence we are forcing scanf() to read characters until we hit enter.
We can use fgets() but one of the problem of it is that it will even read '\n' into array,which will always print the output of next printf() operation on one extra new line.This can cause problem when you want your output to be in tabular form.
int main()
{
char author[301]="\0";//initialize char array to '\0' NULL's
int year;
printf("Insert the name of the author to search: ");
if( scanf(" %300[^\n]", author)!=1 )
{
printf("End of Input or Error Occurred reading Name.\n");
return 1;// return (NON-ZERO) means unsuccessful termination
}
printf("Insert the year: ");
if( scanf("%d", &year)!=1 )
{
printf("End of Input or Error Occurred reading Year.\n");
return 1;// return (NON-ZERO) means unsuccessful termination
}
return 0;
}

Related

Issues with scanf() and accepting user input

I am trying to take in user input with spaces and store it in an array of characters.
After, I want to take in a single character value and store it as a char.
However, when I run my code, the prompt for the character gets ignored and a space is populated instead. How can I take in an array of chars and still be allowed to prompt for a single character after?
void main()
{
char userIn[30];
char findChar;
printf("Please enter a string: ");
scanf("%[^\n]s", userIn);
printf("Please enter a character to search for: ");
scanf("%c", &findChar);
//this was put here to see why my single char wasnt working in a function I had
printf("%c", findChar);
}
scanf("%c", &findChar); reads the next character pending in the input stream. This character will be the newline entered by the user that stopped the previous conversion, so findChar will be set to the value '\n', without waiting for any user input and printf will output this newline without any other visible effect.
Modify the call as scanf(" %c", &findChar) to ignore pending white space and get the next character from the user, or more reliably write a loop to read the read and ignore of the input line.
Note also that scanf("%[^\n]s", userIn); is incorrect:
scanf() may store bytes beyond the end of userIn if the user types more than 29 bytes of input.
the s after the ] is a bug, the conversion format for character classes is not a variation of the %s conversion.
Other problems:
void is not a proper type for the return value of the main() function.
the <stdio.h> header is required for this code.
Here is a modified version:
#include <stdio.h>
int main() {
char userIn[30];
int c;
char findChar;
int i, found;
printf("Please enter a string: ");
if (scanf("%29[^\n]", userIn) != 1) {
fprintf(stderr, "Input failure\n");
return 1;
}
/* read and ignore the rest of input line */
while ((c = getchar()) != EOF && c != '\n')
continue;
printf("Please enter a character to search for: ");
if (scanf("%c", &findChar) != 1) {
fprintf(stderr, "Input failure\n");
return 1;
}
printf("Searching for '%c'\n", findChar);
found = 0;
for (i = 0; userIn[i] != '\0'; i++) {
if (userIn[i] == findChar) {
found++;
printf("found '%c' at offset %d\n", c, i);
}
}
if (!found) {
printf("character '%c' not found\n", c);
}
return 0;
}
scanf("%[^\n]s", userIn); is a bit weird. The s is guaranteed not to match, since that character will always be \n. Also, you should use a width modifier to avoid a buffer overflow. Use scanf("%29[^\n]", userIn); That alone will not solve the problem, since the next scanf is going to consume the newline. There are a few options. You could consume the newline in the first scanf with:
scanf("%29[^\n]%*c", userIn);
or discard all whitespace in the next call with
scanf(" %c", &findChar);
The behavior will differ on lines of input that exceed 29 characters in length or when the user attempts to assign whitespace to findChar, so which solution you use will depend on how you want to handle those situations.

why first gets() function is not working?

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.

scanf() to get in the string on the second time

What is wrong with the scanf() to get in the string on the second time, I can't input my string on the second time.
I am not sure with the error that occurs, I can't get this program function well
#include <stdio.h>
#include <stdlib.h>
int main()
{
//variables decleration
char staff_name1[31];
char staff_name2[31];
float sales1, sales2;
//input
printf("Enter staff name\t> ");
scanf("%[^\n]s", staff_name1);
printf("Enter sales amount\t> ");
scanf("%f", &sales1);
printf("\nEnter staff name \t> ");//ERROR,CAN'T INPUT MY STRING
fflush(stdin);
scanf("%[^\n]s", staff_name2);
printf("\nEnter sales amount\t> ");
scanf("%f", &sales2);
printf("\n");
//output
printf("Staff Name\t\t\t\tSales Amount\n");
printf("===================\t\t=============\n");
printf("%-20s \t%12.2f\n", staff_name1, sales1);
printf("%-20s \t%12.2f\n", staff_name2, sales2);
}
my output of this code is as below:
warning: this program uses gets(), which is unsafe.
Enter staff name > kh s
Enter sales amount > 134.14
Enter staff name >
Enter sales amount > 141243.14
Staff Name Sales Amount
=================== =============
kh s 134.14
141243.14
I can't input the second staff name. Can anyone please help me solve this??
fflush(stdin);
is undefined behaviour in standard C. To flush the newline character, you could simply use getchar() instead.
printf("\nEnter staff name \t> ");
getchar();
scanf("%[^\n]s", staff_name2);
I would also use fgets() instead of scanf to read a line and trim the newline if necessary, which offers better control over invalid inputs being entered by user and against buffer overflows.
You have three problems.
I see that you use %[^\n]s. It is wrong. The s isn't part of the %[ specifier. So use %[^\n] instead of %[^\n]s
After you enter the value for sales1, you press Enter. This character stays in the stdin(standard input stream). And when the next character for %[^\n] is \n, it will fail. Fix this problem by adding a space before %[^\n].
Using fflush on stdin invokes Undefined Behavior as per the C11 standard, although the behavior is well defined in some implementations. It is better to remove it so that your code will be more portable.
Additional notes:
You can limit the amount of characters to be scanned so that you can avoid buffer overflows.
You can check the return value of scanf to make sure it is successful. All the scanf in your program will return 1 on success.
Fixed Program:
#include <stdio.h>
#include <stdlib.h> //Unused header
int main()
{
char staff_name1[31];
char staff_name2[31];
float sales1, sales2;
printf("Enter staff name\t> ");
if(scanf(" %30[^\n]", staff_name1) != 1)
{
printf("Could not scan staff_name1");
return -1; //Exit main with a return value of -1
}
printf("Enter sales amount\t> ");
if(scanf("%f", &sales1) != 1)
{
printf("Could not scan sales1");
return -1; //Exit main with a return value of -1
}
printf("\nEnter staff name \t> ");
//fflush(stdin); UB!
if(scanf(" %30[^\n]", staff_name2) != 1)
{
printf("Could not scan staff_name2");
return -1; //Exit main with a return value of -1
}
printf("\nEnter sales amount\t> ");
if(scanf("%f", &sales2) != 1)
{
printf("Could not scan sales2");
return -1; //Exit main with a return value of -1
}
printf("\n");
//output
printf("Staff Name\t\t\t\tSales Amount\n");
printf("===================\t\t=============\n");
printf("%-20s \t%12.2f\n", staff_name1, sales1);
printf("%-20s \t%12.2f\n", staff_name2, sales2);
}

fgets limiting input length

When I'm inputting data like a last name I have got it so it limits it to 10 characters, but when I try to enter the last name, the characters that were excluded from the first name are put into the last name. For example, if I enter aaaaaaaaaab it will keep the a's but the b will be put into last name.
Any suggestions how I would fix this? I want it to limit the length to the correct amount.
printf("you chose add new record\n");
printf("enter the person information: \n");
printf("Please enter the first name: \n");
//limits to size 10
char namein[11];
fgets(namein, 11, stdin);
printf("the first name was: %s\n", namein);
printf("Please enter the last name: \n");
//limits to size 20
char lastin[21];
fgets(lastin, 21, stdin);
printf("the last name was: %s\n", lastin);
Examine the result of using fgets().
If the buffer contains a \n, no need to look for more. Otherwise consume potential extra data until '\n' or EOF.
int ConsumeExtra(const char *buf) {
int found = 0;
if (strchr(buf, '\n') == NULL) {
int ch;
// dispose of extra data
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
found = 1;
}
}
return found;
}
char namein[11];
if (fgets(namein, sizeof namein, stdin) == NULL) Handle_EOForIOError();
if (ConsumeExtra(namein)) Handle_ExtraFound();
Note: Recommend not being so small with input buffers. Better to reads into a general large buffer and then qualify the input before saving to namein. IOWs, prefer to keep input and scanning/parsing separate.
char buffer[100]
char namein[11];
if (fgets(namein, sizeof buf, stdin) == NULL) Handle_EOForIOError();
if (ConsumeExtra(buf)) Handle_InsaneLongInput();
int n = 0;
sscanf(buffer, "%10s %n", namein, &n);
if (n == 0 || buf[n]) Handle_NothingOrExtraFound();
You have to read the entire input buffer before doing the next read. Such an operation is called "draining" the input.
So your code should look like
get the first name
read the first name
drain the input
print the prompt for the last name
read the last name
draining the input looks roughly like
while (there is data that can be read) {
read a character
}

Calling scanf() after another string input function creates phantom input

Here's a small program:
#include <stdio.h>
int main() {
char str[21], choice[21]; int size;
while(1){
printf("$ ");
fgets(str, 20, stdin);
printf("Entered string: %s", str);
if(str[0] == 'q') {
printf("You sure? (y/n) ");
scanf("%s", choice);
if(choice[0] == 'y' || choice[0] == 'Y')
break;
}
}
return 0;
}
It reads a string using fgets(). If the string starts with a q, it confirms if the user wants to quit, and exits if the user types y.
When I run it and type q, this happens:
$ q
Entered string: q
You sure? (y/n) n
$ Entered string:
$
Note the $ Entered string:. Clearly, fgets() got an empty character or something as input, even though I didn't type anything.
What's going on?
As described in other answer scanf call leaves the newline in the input buffer you can also use getchar() after scanf like this :
scanf("%20s", choice);// always remember( & good) to include field width
// in scanf while reading
Strings otherwise it will overwrite buffer in case of large strings `
getchar(); //this will eat up the newline
Besides , you should also use fgets like this :
fgets(str,sizeof str, stdin); //Its better
It because the scanf call reads a character, but leaves the newline in the buffer. So when you next time call fgets is finds that one newline character and reads it resulting in an empty line being read.
The solution is deceptively simple: Put a space after the format in the scanf call:
scanf("%s ", choice);
/* ^ */
/* | */
/* Note space */
This will cause scanf to read and discard all training whitespace, including newlines.
Use a 'char' of a specific size char choice [1]
OR
char c[1];
c = getchar();
if(c[0] == 'y' || c[1] == 'y'){
// DO SOMETHING
}

Resources