Why does C skip scanf() [duplicate] - c

This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 4 months ago.
So I was writing a quick program to get information about a patient from a hospital and it keeps skipping the scanf() at a certain point (at around line 34) and moves on to the scanf() after it. Here's the part that keeps bothering the life out of me:
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
int main(void){
char choice_1, choice_2, *blood_group, *spec_conditions, *allergies;
printf("Enter the patient's medical details.\n\n");
printf("Enter your blood group: ");
scanf("%s",&blood_group);
printf("Does the patient have any allergies:(y/n)");
scanf("%c",&choice_2);
if (choice_2 == 'y'){
printf("Kindly enter the allergies: ");
scanf("%s",&allergies);
}else{
allergies = "No allergies";
}
printf("\nDoes the patient have any special conditions:(y/n)");
scanf("%c",&choice_1);
if (choice_1 == 'y'){
printf("Kindly enter the condtion: ");
scanf("%s",&spec_conditions);
}else{
spec_conditions = "No special conditions";
}
printf("Displaying details...\n");
sleep(2);
system("cls");
printf("\t\t\tPATIENT DETAILS\n");
sleep(1);
return 0;
}

Problem 1:
char *blood_group, *spec_conditions, *allergies;
scanf("%s",&blood_group);
scanf("%s",&allergies);
scanf("%s",&spec_conditions);
What this does is it attempts to write a string of an unknown length to the address of char * variables, resulting in a 'buffer' overflow if the string is larger than a pointer, or a wild pointer that points to a random location.
Do not pass the address of the pointer to scanf, pass the pointer itself. Furthermore, the pointer must point to writable memory. This can be done by declaring it as an array.
Problem 2:
scanf("%c") reads the newline left when the user hits enter to read the string and moves on. Use scanf(" %c") instead to skip leading whitespace and read the actual character.
Try:
int main(void){
char choice_1, choice_2, blood_group[256], spec_conditions[256], allergies[256];
printf("Enter the patient's medical details.\n\n");
printf("Enter your blood group: ");
scanf("%255s",blood_group);
printf("Does the patient have any allergies:(y/n)");
scanf(" %c",&choice_2);
if (choice_2 == 'y'){
printf("Kindly enter the allergies: ");
scanf("%255s",allergies);
}else{
strcpy(allergies, "No allergies");
}
printf("\nDoes the patient have any special conditions:(y/n)");
scanf(" %c",&choice_1);
if (choice_1 == 'y'){
printf("Kindly enter the condtion: ");
scanf("%255s",spec_conditions);
}else{
strcpy(spec_conditions, "No special conditions");
}
printf("Displaying details...\n");
sleep(2);
system("cls");
printf("\t\t\tPATIENT DETAILS\n");
sleep(1);
return 0;
}

Related

Non-NULL User input

I'm trying to understand the whole concept of pointers, structures, etc so I've created a program that gets user input for two different books and then swaps the info of the two books. I had no trouble doing that, however, a problem arose- when I pressed enter the name of the book would be plain blank and at the output I would, of course, see a blank space. My problem is, how am I able to limit the user to input any letter (A-Z, a-z) and not blank space?
A string of characters when input to an array, they get saved in consecutive memory addresses. We also know that 'NULL' is represented as '\0' in arrays.
With the above things in mind, I performed multiple tests in which, ALL of them failed to yield the desired results.
Below are some attempts that I made.
1st Attempt
while (pBook1->name[0] == '\0')
{
printf("\n Please enter a valid book name: ");
fgets(pBook1->name, MAX, stdin);
}
2nd Attempt
while (strcmp(pBook1->name, ""))
{
printf("\n Please enter a valid book name: ");
fgets(pBook1->name, MAX, stdin);
}
Also, consider the following code as the source code of my program:
#include <stdio.h>
#include <string.h>
#define MAX 50
struct Books
{
char name[MAX];
int ID;
float price;
};
void swap(struct Books *, struct Books *);
void main()
{
struct Books Book1, Book2, *pBook1, *pBook2;
pBook1 = &Book1;
pBook2 = &Book2;
// Input for the 1st book
printf("\n 1st Book \n ------------------------------");
printf("\n Enter the name: ");
fgets(pBook1->name, MAX, stdin);
while (pBook1->name[0] == '\0')
{
printf("\n Please enter a valid book name: ");
fgets(pBook1->name, MAX, stdin);
}
printf("\n Enter the ID: ");
scanf("%d", &pBook1->ID);
printf("\n Enter the price: ");
scanf("%f", &pBook1->price);
// Input for the 2nd book
printf("\n 2nd Book \n ------------------------------");
printf("\n Enter the name: ");
fgets(pBook2->name, MAX, stdin);
while (pBook2->name[0] == '\0')
{
printf("\n Please enter a valid book name: ");
fgets(pBook2->name, MAX, stdin);
}
printf("\n Enter the ID: ");
scanf("%d", &pBook2->ID);
printf("\n Enter the price: ");
scanf("%f", &pBook2->price);
printf("\n Let's swap the info of the two books...");
swap(pBook1, pBook2);
printf("\n The info of the two books is now:");
printf("\n------------------------------ \n 1st Book \n ------------------------------------");
printf("\n Name \t\t ID \t Price \n %s \t\t %d \t %f", pBook1->name, pBook1->ID, pBook1->price);
printf("\n------------------------------ \n 2nd Book \n ------------------------------------");
printf("Name \t\t ID \t Price \n %s \t\t %d \t %f", pBook2->name, pBook2->ID, pBook2->price);
}
void swap(struct Books *pB1, struct Books *pB2)
{
char temp[MAX];
strcpy(temp, pB1->name);
strcpy(pB1->name, pB2->name);
strcpy(pB2->name, temp);
int tempID = pB1->ID, tempPrice = pB1->price;
pB1->ID = pB2->ID;
pB2->ID = tempID;
pB1->price = pB2->price;
pB2->price = tempPrice;
}
fgets reads until it encounters EOF, \n or N-1 bytes have been read. So if a user of your program presses enter, it will read \n and stop. Which means that pBook1->name[0] == '\n'. That is why your check for equality with "" fails and why pBook1->name[0] == '\0' fails.
See this example.
That means that you need to check for \n and \0 in case the user entered Ctrl-D which is how you enter EOF on *nix systems.
When you press enter pBook1->name[0] will become \n. You can use some functions as strlen to be sure there something in name.

scanf stops working after first one [C]

I am trying to have the user enter for the first, middle, and last name in my struct. The first scan works fine, any after that do not work. Here's my code so far
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include "contacts.h"
int main (void)
{
// Declare variables here:
struct Name names;
char yesNo;
// Display the title
printf("Contact Management System\n");
printf("-------------------------\n");
// Contact Name Input:
printf("Please enter the contact's first name: ");
scanf ("%d", &names.firstName);
printf("Do you want to enter a middle initial(s)? (y or n): ");
scanf(" %c", &yesNo);
while (yesNo == 'y' || yesNo == 'Y') {
printf("Please enter the contact's middle initial(s): ");
scanf(" %c%d", &names.middleInitial);
yesNo = 'n';
}
printf("Please enter the contact's last name: ");
scanf(" %c%d", &names.lastName);
Here's the struct in my header file
struct Name {
char firstName[31];
char middleInitial[7];
char lastName[36];
};
When I enter more than one character the program ends, when I enter just one character, the program skips the second scanf. I had the program working beforehand but I realized I needed to use structs so I switched from int's to the struct, and I haven't been able to make it work this way.
You are using scanf wrong.
scanf ("%d", &names.firstName);
names.firstName is a char array, but you are using %d which expects a
pointer to int, you are passing a pointer to an array. This is correct:
scanf("%30s", names.firstName);
Then you do
scanf(" %c%d", &names.middleInitial);
which has two errors: you are giving two conversion but passing only a on
pointer, and you are again passing the wrong pointer. Correct:
scanf("%6s", names.middleInitial);
and the same applies for scanf(" %c%d", &names.lastName);, the correct version
scanf("%35s", names.lastName);
In general, when using scanf with %s, you will have the problem that newline
and other strings are kept in the input buffer. This happens because %s
matches a sequence of non-white-space characters, so the newline (entered when
ENTER is pressed) will remain in the input buffer. Another example is
if the user enters two word separated by at least an empty space (like Hello Word),
%s would only read Hello. Subsequent calls of scanf may fail if they don't
anticipate this. That's why the best strategy is to clean the
buffer, use this function:
void clean_file_buffer(FILE *fp)
{
int c;
while((c = fgetc(fp)) != '\n' && c!=EOF);
}
And the you can use it like this:
printf("Please enter the contact's first name: ");
scanf ("%30s", names.firstName);
clean_file_buffer(stdin);
that takes care of left overs.
If you however want to have more control over the whole line, then you should
use fgets instead to read the whole line and then you can use sscanf to
parse it.
scanf("%s", names.firstName);
scanf(" %c", &yesNo);
scanf(" %s", names.middleInitial);
scanf(" %s", names.lastName);
or
scanf("%s", names.firstName);
getchar();
scanf("%c", &yesNo);
getchar();
scanf("%s", names.middleInitial);
getchar();
scanf("%s", names.lastName);
getchar();
and when yesNo question, if you typed over 1 character, first character will be into yesNo variable, and other chars will be into next input variable(names.middleInitial).
If you want to check the yesNo more carefully,
input yesNo as string. (but, buffer size check needed. buffer overflow.)
char yesNos[100];
scanf(" %s", &yesNos) ;
if ( yesNos[0]=='y' ) {...}

comparing strings and printing stored strings in C

I am having trouble getting this program to print the strings I enter properly. It keeps telling me that I have not entered data, even when I have. I also can't get the strings to compare to run my if statement. Thank for any help.
#include <stdio.h>
//function prototype
void enterPerson();
void enterChoice();
//global variables
char person[30];
char choice;
int main(void) {
enterPerson();
enterChoice();
printf("Please try the Precipitation Program again.\n");
return 0;
}
void enterPerson(){
// Ask for person name
printf("Please enter name:\n");
scanf("%s", &person);
//-------------------------------------------
printf("person is %s\n", person);
//-------------------------------------------
}
void enterChoice(){
//initialize choice
choice = "M";
//ask what they choose
printf("Do you choose test or rate? (Enter T for test R for rate)\n");
scanf("%c", &choice);
printf("Xchoice is: %c\n", choice);
if ((choice == 'T')||(choice == 'R')){
printf("choice is: %c\n", choice);
}
else{
printf("Incorrect or no data was input at this time\n");
}
}
As mentioned in comments, there are at least 3 problems:
scanf("%s", person); - do not take the address of char array.
scanf(" %c", &choice); - insert space to ignore whitespace.
choice = 'M'; - "M" is a string literal, while choice is char.
There is a linefeed (0xa) character left in the input buffer. You can see it by printing the choice variable after your scanf line with:
scanf("%c", &choice);
printf("c: %x\n", choice);
There are several options to get rid of this. Easiest is explained here.
Also there is a problem in:
scanf("%s", &person);
Character array name in C points to the first character, so you should fix this with:
scanf("%s", person);

If statement not working for marital status

I am creating a program which requires user to enter their marital status.
i want to be able to ask them Yes or No and then use if statements .
my code just skips the if block and prints the else block.
#include<stdio.h>
int main(void)
{
int age;
char marr;
printf("Please enter your age: \n");
scanf_s("%d",&age);
getchar();// getchar() is being used to clear any buffer of any remaining keystrokes that might stll be stored.
printf("Are you married ? (y/n)\n");
scanf_s("%c", &marr);
if (marr == 'y')
printf("Married\n");
else
printf("Unmarried\n");
}
for some reason, whatever I input, i still get the output as unmarried,
no idea why.
Use scanf() instead of scanf_s() in this case or you'll need a buffer size argument if your input parameter is a character. Too you can place a space before %c in the scanf()-statement instead of your getchar()-command.
#include<stdio.h>
int main(void) {
int age;
char marr;
printf("Please enter your age: \n");
scanf("%d",&age);
printf("Are you married ? (y/n)\n");
scanf(" %c", &marr);
if (marr == 'y')
printf("Married\n");
else
printf("Unmarried\n");
}

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);
}

Resources