Why do string input requests always get skipped? - c

I know others have asked similar questions but they are often old posts with outdated code and solutions.
Regardless of whether I use scanf_s or fgets, it always seems to get skipped despite the fact that I have done this the exact same way on other PCs with the same version of VS and they work fine.
int main() {
char name[20];
name[0] = 0;
printf("Enter your name: ");
scanf_s("%[^\n]%*c", &name[0], 20);
printf("\n");
printf("Your name is %s", name);
}
What am I doing wrong that makes this an issue now but not when this is done elsewhere?
EDIT:
After recreating it and only it in another file and seeing a post (and commenting off certain sections and testing it) I now realize that another part of the code is messing with it. Specifically the scanf_s("%d", &age); of the following code:
int main() {
int age;
int ageDifference;
printf("Enter your age: ");
scanf_s("%d", &age);
if (age == 18) {
printf("You are 18 years old.");
}
else if (age > 18) {
ageDifference = age - 18;
printf("It has been %d years since you were 18.", ageDifference);
}
else {
ageDifference = 18 - age;
printf("It will be %d years before you are 18.", ageDifference);
}
printf("\n");
char name[20];
name[0] = 0;
printf("Enter your name: ");
scanf_s("%[^\n]%*c", name, 20);
printf("\n");
printf("Your name is %s", name);
return 0;
}
Screenshot of output: https://prnt.sc/qdo38t
Why is it causing it to skip it though?
Sorry for being such a noob at C too.
FIXED: Adding a space so that scanf_s("%[^\n]%*c", name, 20) is now scanf_s(" %[^\n]", name, 20) fixed it. Also %*c is not needed. Thanks #Weather Vane.

Let us walk through
printf("Enter your age: ");
User input 6 6 Enter
scanf_s("%d", &age);
scanf() reads "66", leaving the '\n' in stdin.
....
printf("Enter your name: ");
scanf_s() attmepts to read the '\n', which does not meet the criteria of "%[^\n]", so scanf_s() stops right away and does not return a 1 - still leaving the '\n' in stdin.
scanf_s("%[^\n]%*c", name, 20)
Code did not check scanf_s() results, Tsk, tsk, and so does not know that name[] remains unchanged.
Using a space as in " %[^\n]%*c" helps, to first consume the left-over '\n', but the best advice is to not use scanf(), scanf_s() at all. Use fgets() to read a line into a string and then parse the string with sscanf(), strtol(), etc.
In all cases, check the return value of input functions.

Related

Problems using fgets multiple times

I am really new to C and I am facing a problem with fgets(). I need to make multiple calls to fgets in order to retrieve 4 pieces of data, a name, age, num1 and num2. I cannot use scanf for this I have to use fgets. However, I am facing problems when I make multiple calls to fgets. And just to clarify I want to read num1 and num2 as strings. Here is my code:
int main(int argc, char const *argv[])
{
/* code */
char name[50];
char ageString[3];
char num1[6];
char num2[6];
printf("Enter your name: ");
fgets(name, 50, stdin);
printf("Enter an age: ");
fgets(ageString, 3, stdin);
printf("Enter num 1: ");
fgets(num1, 6, stdin);
printf("Enter num 2: ");
fgets(num2, 6, stdin);
// replace the trailing '\n' with '\0'
name[strcspn(name, "\n")] = '\0';
ageString[strcspn(ageString, "\n")] = '\0';
num1[strcspn(num1, "\n")] = '\0';
num2[strcspn(num2, "\n")] = '\0';
printf("Your name is: %s, you are %s years old, num1: %s, num2: %s\n", name, ageString, num1, num2);
return 0;
}
Here is what I get outputted in the terminal:
Enter your name: Random
Enter an age: 21
Enter num 1: Enter num 2: 1
Your name is: Random, you are 21 years old, num1: , num2: 1
The program reads name and age fine but the num1 is not being read and the formatting is really off.
If anyone has a fix for this that would be greatly appreciated. Again, I am very new to C so I am still learning.
Thank you!
The problem is that your array sizes are too small. When you type in "21\n" and fgets is called with 3 as the size, it reads 2 characters (not 3) The \n remains, so fgets next reads only the newline. The solution would be to to increase your array size by one (for that specific input) or "Don't skimp on Buffer Size...." (#David C. Rankin)

Scanf is being skipped after the first iteration of the for loop

When the for loop is run for the first time the program waits for the users input. But after the first time the two scanf lines seems to be skipped.
I've commented out the misc code:
#include <stdio.h>
int n = 0;
struct student {
int age;
char name[20];
};
void enterStudents() {
printf("How many students do you want to enter? \n");
scanf("%d", &n);
struct student list[n];
for(int i=0; i<n; i++){
printf("Enter student number %d's age: ", i+1);
scanf("%d", &list[i].age);
printf("Enter student number %d's name: ", i+1);
scanf(" %c", list[i].name);
}
listSort(list);
}
/**int listSort(struct student list[n]) {
char tempName[20];
int tempAge;
for(int i=0; i<n-1; i++){
if(list[n].age < list[n+1].age) {
tempAge = list[n].age;
strcpy(tempName, list[n].name);
list[n].age = list[n+1].age;
strcpy(list[n].name, list[n+1].name);
list[n+1].age = tempAge;
strcpy(list[n+1].name, tempName);
}
}
}**/
int main() {
enterStudents();
}
One problem that beginners often overlook with scanf is that if the conversion
fails or the the conversion converts less characters than the user entered (for
example using %c instead of %s), then scanf leaves the not-converted
characters in the input buffer. A subsequent call of scanf will first try to
convert those characters that are in the input buffer, before it reads again
from the user.
In your case you used %c but the user enters something that is longer than a
single character. Only 1 character was used in the conversion the rest was left
in the input buffer. In the next for iteration scanf("%d") tries to convert
the characters that were left in the input buffer and because the user enter non-digits for the name, scanf fails and the next scanf reads only the first characters and
left the rest behind, etc. That's why it appears that scanf skips the calls.
You should check the return value of scanf, it returns the number of
successful conversion it made. This is great information, if you get less
conversions than expected, then you know the scanf call failed and you can
react to that. Also you may also clean the buffer if you are reading strings,
newlines and word after an empty space are left in the buffer and that can cause
some trouble with subsequent calls of scanf. You can use a function like this:
void clean_stdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
So your function should look like this:
int enterStudents() {
printf("How many students do you want to enter? \n");
if(scanf("%d", &n) != 1)
{
fprintf(stderr, "Could not read from the user\n");
return -1; // failure
}
if(n <= 0)
{
fprintf(stderr, "invalid number of students\n");
return -1;
}
struct student list[n];
for(int i=0; i<n; i++){
printf("Enter student number %d's age: ", i+1);
if(scanf("%d", &list[i].age) != 1)
{
fprintf(stderr, "could not read age from the user\n");
return -1;
}
printf("Enter student number %d's name: ", i+1);
if(scanf("%19s", list[i].name) != 1)
{
fprintf(stderr, "could not read name from the user\n");
return -1;
}
// cleaning stdin
clean_stdin();
}
...
return n; // sucess
}
Note that I've changed the function so that it returns -1 on failure and the
number of students read on success, so the caller can know that something went wrong and get
the number of students at the same time. In general, in order to make your code
more robust, you should never trust the user and you should double check
user input. You have to check that the user didn't enter a negative number for
the student count. The "correct" mind set is "the user is trying to break your
code by entering incorrect data and I have to deal with that". I know, the code
become slightly more larger, but it is more robust and if something fails, you
can narrow down more quickly (based on the error messages) where something went
wrong. In your code, when something fails, you have really no idea where it
could have happened.
Also note that in the name scan I used scanf("%19s", ..) instead of %s. The
reason is that using %s you might overflow the buffer if the name is longer
than the buffer can hold. If the name is longer than 19 characters, it will
overflow the buffer. With "%19s" you are limiting how many characters should
be read, in this case scanf will convert at most 19 characters and ignore the
rest. Why 19 and not 20? You have to use 19, because strings in C are
'\0'-terminated, so the last space in the array should be used for the
'\0'-terminating bytes, hence 19.
Whenever you take input from user where input has sequence as first is any other data type and then character or character array as in your case sequence is integer and then character. First you enter the age of student like 21 now when u press 'enter key' this 'enter' is taken as the input for next character input. Then your input will look like this:
age=21
name='enter' (enter key that you pressed)
Now we can use a function that is fflush(stdin), this will flush out that enter key and allow you to enter name. this code will work:
void enterStudents()
{
printf("How many students do you want to enter? \n");
scanf("%d", &n);
struct student list[n];
for(int i=0; i<n; i++){
printf("Enter student number %d's age: ", i+1);
scanf("%d", &list[i].age);
//enter this line after your first input
fflush(stdin);
printf("Enter student number %d's name: ", i+1);
scanf(" %s", list[i].name);
}
listSort(list);
}

A nesting 'if' statement does not work [duplicate]

This question already has answers here:
fgets doesn't work after scanf [duplicate]
(7 answers)
Why does a space in my scanf statement make a difference? [duplicate]
(3 answers)
Closed 5 years ago.
I'm trying to code very simple code, and here it is:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int age;
char gender;
printf("How old are you? \n");
scanf("%d", &age);
printf("What is your gender? (m/f) \n");
scanf("%c", &gender);
if ((age >= 18 && gender == 'm')){
printf("You may enter this website ");
if (age <= 20)
{
printf("dude.");
}
}
if ((age >= 18 && gender == 'f')) {
printf("You may enter this website ");
if (age <= 20)
{
printf("young lady.");
}
}
else if (age < 18)
{
printf("Nothing to see here! \n");
}
return 0;
}
In the code above, I'm trying to use a nesting if statement. But it doesn't work, not as I wish. After I enter the age, it prints out the sentence: What is your gender? (m/f).
When the second sentence is printed out, it terminates. But I don't know why.
I want the user be able to enter the gender and based on the entered gender and age it should print out a sentence.
Could you please give me a hint?
There is nothing wrong with the logic of your code, so the most likely reason for the behavior that you see is this line:
scanf("%c", &gender);
Since the line follows reading of an int, the '\n' that remains in the buffer gets assigned to gender immediately.
You can fix this by adding a space in front of %c to ignore newline:
scanf(" %c", &gender);
You can also reduce the code somewhat by combining a few checks:
if (age >= 18){
printf("You may enter this website ");
if (age <= 20) {
printf("%s.\n", gender == 'm' ? "dude" : "young lady");
}
}
Replace scanf("%c", &gender) with scanf(" %c", &gender)
This is because when you enter your age and press enter key, your age will be stored in age variable but '\n'(enter key) is still present in the buffer which will be read by the gender.
So, you can do these things-
scanf("%d\n",&age)
or
use
scanf("%d", &age);
getchar();

Why procedure if in C doesn't work with char

I am writing a simple quiz in C (using CodeBlocks 13.12)
It compiles, but doesn't work in second question. Whatever I will input, it always give answer 'that's sad'.
I can't understand what is wrong.
I came to this, where if I comment line 13 ( scanf("%d", &age); ) it's starting works ok for second question.
What the problem is?
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <clocale>
int main()
{
int age;
char S1;
printf("How old is your dog? \n");
scanf("%d", &age);
if (age <= 7)
{
printf(" very young. the end \n");
return 0;
}
else
{
printf("old dog. \n \n");
}
//question2
printf("Do you like dogs? y/n \n");
scanf("%c%c", &S1);
if (S1 == 'y')
{
printf("hey, that's nice \n");
}
else
{
printf(" that's sad :( . \n");
return 0;
}
return 0;
}
You cause undefined behavior by
scanf("%c%c", &S1);
scanf reads two chars, one stored in S1, one stored in some location on the stack because scanf expects a second char* to be supplied.
If your intention is to ignore the newline following the actual character, write
scanf("%c%*c", &S1);
Change the second scanf() to
scanf(" %c", &S1);
This would escape the left out newline character \n in the input buffer.
Plus, you are reading one char in this. So you need only one %c
scanf("%c", &S1);
is the correct way to input one character ,

C - if/else statement

I'm fairly competent with if/else statements, and this is a really old assignment that I ended up turning in partially complete. But I still wanted to know exactly why my code wouldn't work.
I want my user to input name, height, and sex. My code will then display an entire sentence that says "Name is X cm tall and is a male" or "Name is X cm tall and is a female."
When I input name and enter, it immediately then skips displays both the height AND the sex. Regardless of what I input after that, it then ends the program.
Input name: Jack
Input height in cm: 180
sex(M/F):
Computer $
I've been playing around with this code for a while now, but I have been stuck for a while now. Any help would be greatly appreciated. Here is my code:
#include<stdio.h>
int main() {
char name[30];
char sex;
float height;
printf("Input name: ");
scanf("%s", name);
fflush(stdin);
printf("Input height in cm: ");
scanf("%f", &height);
fflush(stdin);
printf("sex(M/F): ");
scanf("%c", &sex);
if (sex == 'M')
{
printf("%s is %f cm tall and male", name, height);
}
else if (sex == 'F')
{
printf("%s is %f cm tall and female", name, height);
}
printf("\n");
return 0;
}
From what I can see it only skips the sex part - which is very sad to be honest :-)).
it immediately then skips displays both the height AND the sex
Input name: Jack Input height in cm: 180 sex(M/F): Computer $
You can try this:
scanf(" %c", &sex);
^
The space causes scanf to eat blanks before reading a character.
fflush(stdin) is a very bad idea (undefined behavior). You should replace this call with an other function call, for example this one :
static void
clean_stdin(void)
{
int c;
do {
c = getchar();
} while (c != '\n' && c != EOF);
}
With it, it seems working.
You're missing an ampersand on line 9:
scanf("%s", name);
shoul be:
scanf("%s", &name);
maybe this helps
You can also try this
printf("sex(M/F): ");
scanf("%s", &sex);
To read a single character from stdin you have to use getchar() instead of scanf("%c", &c)
Or change the variable type of sex to char[2] and use scanf("%s", sex)

Resources