"scanf with printf" vs "fgets with printf" - c

I know about the difference and the advantage/disatvantage of using scanf and fgets.
I don't understand the relations between printf and this two C standard functions.
I have this simple code:
void print_choice(char * list, char * choice)
{
/* check parameters */
if(!list || !choice)
return;
printf("list of users: %s\n", list);
printf("Choice -- ? ");
/* scanf("%s", &choice); */
/* fgets(choice, 20, stdin); */
}
int main()
{
char choice[20];
char * list = "marco:dario:roberto:franco";
print_choice(list, choice);
printf("choice = %s\n", choice);
return 0;
}
if I use fgets, printf print the result correctly on stdout;
If I use scanf, printf` doesn't print anything on stdout.
Why this behaviour?

You used scanf("%s", &choice); which passes a char ** to scanf() when it expects a char *.
Drop the &.
If your compiler wasn't complaining, you either haven't turned on enough warnings or you need a better compiler.

Change
scanf("%s", &choice);
to
scanf("%s", choice);

you have to use
scanf("%s", choice);
instead of
scanf("%s", &choice);

Changing this scanf("%s", &choice); to this scanf("%s", choice); will cause scanf and fgets to show almost similar behavior.
scanf requires an address as an argument. It goes on and stores the input from stdin after converting it based on the supplied format specifier. Here the format specifier is %s so it will try to store the input at the address pointed by address of choice . What you need here is the address from where the choice array will begin,which in this case is choice itself.

Related

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' ) {...}

Function execution not waiting in do-while loop [duplicate]

I tried this code below, but it seems scanf("%c") is skipped. It only asks me to enter name and age and skips the lines below that. It just print the text in the printf above the if statements. Can anyone help?
#include<stdio.h>
int main()
{
int age;
char sex;
char name[20];
char status;
printf("Enter your last name\n");
scanf("%s", &name);
printf("Enter your age\n");
scanf("%d", &age);
printf("Enter sex (M/F)\n");
scanf("%c", &sex);
printf("your status,married, single,irrelevant (M/S/I)\n");
scanf("%c", &status);
if(age>=16 && sex=='M')
printf("hello, Mr %s\n", name);
if(age<16 && sex =='M')
printf("hello, Master %s\n", name);
if(sex=='F' && status=='M')
printf("hello, Mrs %s\n", name);
if(sex=='F' &&(status=='S' ||status=='I'))
printf("hello,miss %s\n", name);
}
Change
scanf("%c", &sex);
to
scanf(" %c", &sex);
^
space
and
scanf("%c", &status);
to
scanf(" %c", &status);
^
space
The problem is because of trailing newline characters after your second call to scanf(). Since it is of %d type specifier, when you press Enter A newline character ( '\n' ) is left in the stream and the next scanf() tries to read that newline character, and thus, it seems as though it just skipped input, but in fact, it read the newline character.
So, the newline character is stored in the variable sex, and thus, it skips asking you for input for that variable.
Unless you are interested in whitespace like newlines, do not use %c. Simply use the string conversion %s and use the first character of the input.
Rationale: All scanf conversion specifiers except %c ignore white space including newlines. They are designed to read sequences of input tokens (numbers, words) where the amount and nature of white space is irrelevant. The words can all be on the same line, or each word on a different line; scanf wouldn't care unless you force single character reads with %c which is almost never necessary.
Change your code to
#include<stdio.h>
int main()
{
int age;
char sex;
char name[20];
char status;
printf("Enter your last name\n");
// scanf("%s", &name);
fgets(name,20,stdin);
printf("Enter your age\n");
scanf("%d", &age);
printf("Enter sex (M/F)\n");
scanf(" %c", &sex);
printf("your status,married, single,irrelevant (M/S/I)\n");
scanf(" %c", &status);
if(age>=16 && sex=='M')
printf("hello, Mr %s\n", name);
if(age<16 && sex =='M')
printf("hello, Master %s\n", name);
if(sex=='F' && status=='M')
printf("hello, Mrs %s\n", name);
if(sex=='F' &&(status=='S' ||status=='I'))
printf("hello,miss %s\n", name);
return 0;
}
Here, I have added an extra space before the format specifier %c, to accommodate any previous input like newline (\n). Another alternative method is to use getchar() immediately before you take any character input.
Also, if you perform string input with scanf, it will not read the input after encountering a whitespace. So, instead use fgets for taking any string input which might contain spaces.
Another thing I changed in your code (trivial) is int main() and return 0.
This happens because blankspace is also treated as a character and and happens when you press enter.
So Leave a space.
scanf(" %c",&something);
You can do the following for all scanfs.
scanf("%c\n",&smth);
And then enter the values one by one separating them by newlines (press Enter).
This helped me too when I had the same problem.
scanf("%c*",&smth);
That makes scanf skip any other characters that a user might input, including newlines.
Note: use appropriate format strings for each type (%s for strings, %d for integers, etc).

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

Comparing strings in C using strcmp

I am trying to learn to program in C but am having trouble with manipulating strings as C treats strings as arrays.
My aim was to make a program that stores the users first name and surname.
Here is my progress:
#include <stdio.h>
int main(int argc, const char * argv[]) {
//defining the variables
char first_name[100];
char surname[100];
char ch[2];
// Asking for the first name and storing it
printf("What's your first name?\n");
scanf("%s", first_name);
// Prints the first name
printf("Hey %s!\n",first_name);
//Asks the user if they want to store their surname
printf("Would you like to tell me your second name? This is optional so type 'Y' for yes and 'N' for no.\n");
scanf("%s", ch);
//validate if they want to store it or not
if (ch == "Y"){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
return (0);
}
However, with this code, I get an error because my IDE(xCode) tells me to use the strcmp function. I then edited the code to become this:
if (strcmp(ch, "Y")){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
However variable ch is not a literal and so is not comparable.
Sidenote
I did try to compare two literals too, just to see how it works:
char *hello = "Hello";
char *Bye = "Bye";
if (strcmp(hello, Bye)){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
But even this gave an error:
Implicitly declaring library function 'strcmp' with type 'int (const *char, const *char)'
I believe I am not able to do this due to my lack of experience so it would be much appreciated if you could help me understand what I'm doing wrong and how I can fix the problem.
You need to include the appropriate header:
#include <string.h>
Also note that your desired logic probably calls for:
if (!strcmp(hello, Bye))
Instead of:
if (strcmp(hello, Bye))
Since strcmp returns 0 in case of equality.
There are several issues you should correct concerning how you handle input with scanf. First always, always validate the number of successful conversions you expect by checking the return for scanf. Next, as mentioned in the comment, there is NO need to include <string.h> in your code to make a one-letter comparison. Use a character comparison instead of a string comparison. Lastly, always limit your input to the number of characters available (plus the nul-terminating character.
Putting the bits together, you could do something like the following:
#include <stdio.h>
#define MAXN 100
int main (void) {
char first_name[MAXN] = "", surname[MAXN] = "";
int ch;
printf ("What's your first name?: ");
if (scanf ("%99[^\n]%*c", first_name) != 1) {
fprintf (stderr, "error: invalid input - first name.\n");
return 1;
}
printf ("Hey %s!\n", first_name);
printf("Enter surname name? optional (Y/N) ");
if (scanf("%c%*c", (char *)&ch) != 1) {
fprintf (stderr, "error: invalid input - Y/N\n");
return 1;
}
if (ch != 'y' && ch != 'Y') /* handle upper/lower case response */
return 1;
printf ("Enter your surname?: ");
if (scanf (" %99[^\n]%*c", surname) != 1) {
fprintf (stderr, "error: invalid input - surname\n");
return 1;
}
printf ("\nYour whole name is : %s %s\n", first_name, surname);
return 0;
}
Example Use/Output
$ ./bin/firstlast
What's your first name?: David
Hey David!
Enter surname name? optional (Y/N) Y
Enter your surname?: Rankin
Your whole name is : David Rankin
Look it over and let me know if you have any questions.
There are two problems here. Firstly you need to see what value is returned by the strcmp and secondly you must use the approprate hedder.
You must use:
#include <string.h>
Secondly, you must edit your if-else statement so it is like this:
if (strcmp(ch, "Y") == 0){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
We do this because the strcmp function returns a negative value if ch is smaller than "Y", or a positive value if it is greater than "Y" and 0 if both strings are equal.

why i can't execute after system("CLS")?

i can't execute after typing password. it gives me a force closed on windows. i'm not good at C. Anyone can help me?
int i;
char user, pass[4], pwd, a;
printf("insert Username : ");
scanf("%s", &user);
printf("insert Password <4 char> : ");
scanf("%c", &pass);
for(i=0;i<4;i++)
{
pwd = getch();
pass[i] = pwd;
pwd = '*' ;
printf("%c",pwd);
}
pass[i] = '\0';
printf("\n");
system("pause");
system("CLS");
printf("username %s", user);
getch();
system("pause");
When output is to a terminal, stdio is line-buffered by default. So you won't see the output of printf() until you print a newline (or print enough to fill the buffer), or explicitly flush the buffer. So change to:
printf("username %s\n", user);
or call fflush(stdout) after that printf.
The CLS has nothing to do with the problem.
Your string pass[4] is too short. After the loop
for(i=0;i<4;i++)
the var i will be 4. You then write beyond the end of the array with
pass[i] = '\0';
which is Undefined Behaviour and can easily break the system. Also your formatting methods are reversed between char and string. You have
scanf("%s", &user);
...
scanf("%c", &pass);
These should be
scanf("%c", &user);
...
scanf("%s", pass); // don't use the & here
// char user[6];
scanf("%s", &user); // scanf("%5s",user);
user is char variable . It can't contain more than one character . Use a char array.
scanf("%c", &pass); // use this scanf("%3s",pass);
pass is a char array not a char variable. Use specifier %s for this .
These are causing problems.

Resources