How can I make scanf() with multiple inputs ignore the others? - c

scanf("%s %d %s %d",word1,&num1,word2,&num2);
so when the user inputs "quit", its supposed to stop asking for the other 3 inputs. however it asks me to input another "quit" probably because there are 2 %s in the format
is there anyway around this?
EDIT: because it has to get 4 inputs in a loop, unless a quit is inputted.

scanf is a very blunt tool that is not good at talking to unstructured inputs (including humans :-) ). In general, if you are interacting with a person, you should start with fgets to read a line, then pick the resulting line apart however is most convenient, possibly including sscanf.
It's worse than you think because the %d directive will jam up if you feed it something that is not scan-able as an integer. For instance, if you enter quit now, the first %s directive will read the word quit but the %d will leave now in the input stream, causing scanf to return 1 (one successful conversion-and-assignment). The next attempt to read a string will obtain and consume the now; to naive code, this will seem like it was a later, second input line, rather than a continuation of the first one.

#include <stdio.h>
#include <string.h>
scanf("%s ", word1);
if (strcmp(word1, "quit") != 0)
scanf("%d %s %d", &num1, word2, &num2);

Related

I want to make a time calculator and, there is a need to read a single character, but I tried many way it won't work

this is my program, this is not complete yet but, when I run this program, the single character reading part of it won't read, I checked without adding (&)ampersand. I tried many ways with arrays and so on, but I can't get the result. please help
#include <stdio.h>
#include <stdlib.h>
int main()
{
int F,S,E,SM,EM;
char t1,t2;
//*S=starting time*//
//*SM=start minute*//
//*F=ending time*//
//*FM=end minute*//
printf("\nEnter the start time: Hour : Minute");
scanf("%d %d",&S,&SM);
printf("\nEnter a for AM Enter p for PM");
scanf(" %c",&t1);//problem
printf("\nEnter end time: Hour: Minute");
scanf("%d %d,",&E,&EM);
printf("\nEnter A for AM: Enter P for PM");
scanf(" %c ",&t2);//problem
return 0;
}
}
Scanf() will try to consume ALL the input, which means that the '\n' from pressing enter will carry over to the next scanf call. This is alleviated by you using a leading space character in your format " %c". However, if the format of the input does not exactly match the actual input, i. e. format is "%d %d", but the input is, say " 1 1", scanf() will fail to write the format. I think this is why it's failing for you after compiling and testing out your code.
Consider adding some logging and error checking into this code snippet, so that it's easier to pin down these errors. Even something as simple as printf("%d %d\n", S, SM); after a scanf() call is much better than not tracking your results at all.

Variable scanf inputs

How exactly would you deal with having a variable amount of scanf inputs?
I'm scanning commands, some of them are 1. word commands but some require numeric argument. Does scanf allow the following?
scanf(" %s %d", command, argument);
Would that ignore the "argument" if only one value was inputed?
The other option i though of was
scanf(" %s", command)
if (strcmp(command, "somethin") {
scanf("%d", argument); }
But that would create a newline right? the terminal has to recieve the input in form of "> command argument"
SO, my question is, how to solve the problem of having variable number of inputs.
No, it won't "create a newline". scanf is completely unaware of any newlines. scanf treats the input stream as a linear sequence of data separated by whitespace. Newline is just whitespace, no different from any other whitespace. The only scanf format specifiers that can "see" newlines are %c and %[]. Your %s and %d are completely newline-agnostic.
Which means that your second example is doing it right (within the natural limitations of scanf). It won't "create a newline". It will read a single line, if you supply the input in a single line (like somethin 42).
You might actually run into the "opposite" problem: if the user forgets to input the required argument in a single line, the next scanf will wait for it on the next line. And on the next line. And on the next line... until he user finally supplies it. I'm not sure this behavior is desirable for you. If not, then a better idea would be to use dedicated line-based input through fgets and then parse the line manually.
P.S. There's no reason to prepend %s and %d with spaces.

What am I doing wrong? (C)

I really have no idea what I'm doing wrong with this. Every time I compile it, at the fourth user input, it just stops and shows the "processes returned" stuff.
#include <stdio.h>
#include <conio.h>
int main() {
char firstname[15], class, swordch0c1, swordch0c2;
int health, healthtot, armor, armortot;
printf("Hello there! Could I have your first name?\n>");
scanf("%s", firstname);
printf("\n---------------------The Legend of %s---------------------", firstname);
printf("\nPress Enter to continue.");
getch();
printf("\n\n\nYou are %s, a(n): \nA.Swordsman\nB.Assassin\nC.Archer\nD.Mage\n>", firstname);
scanf(" %c", &class);
/*swordsman story starts here*/
if (class=='a' || class=='A')
{
printf("\n\nThere you stand, at your boring everyday post.\nWhen you joined the army, you thought it would be more exciting than this.\nJust then, you see your general walking towards you.");
printf("\n\nYou quickly improve your posture. \"Soldier, I have an opportunity for you\"\nA.\"Really? What is it?\"\nB.\"I'm not interested\"\n>");
scanf(" %c", &swordch0c1);
if (swordch0c1=='b'||swordch0c1=='B')
{
printf("\n\"But... I didn't even tell you what it was. Okay, suit yourself\" You are DOOMED to a life of boredom.\n\n\n\n\n");
}
if (swordch0c1=='a'||swordch0c1=='A')
{
printf("\n\n\n\"Well, you see, there's this dragon. He's been causing big problems.\nHe's destroyed villages, harrassed the priests on the mountain,\n");
...
edit:It does allow me to put in the fourth input. after hitting enter, it shows the processes returned stuff.
This line is almost definitely the problem:
scanf(" %c", &swordch0c1);
You are asking to read a single character, however to actually enter a character you have to type two characters: AEnter. This scanf call will read the 'A', and the next scanf call will read the '\n' (the Enter) key, which is still in the input buffer.
I suggest using fgets() for all user input. It's a lot easier to deal with that way, because it matches the way users actually enter input (line of text plus Enter).

Using fscanf() vs. fgets() and sscanf()

In the book Practical C Programming, I find that the combination of fgets() and sscanf() is used to read input. However, it appears to me that the same objective can be met more easily using just the fscanf() function:
From the book (the idea, not the example):
int main()
{
int age, weight;
printf("Enter age and weight: ");
char line[20];
fgets(line, sizeof(line), stdin);
sscanf(line, "%d %d", &age, &weight);
printf("\nYou entered: %d %d\n", age, weight);
return 0;
}
How I think it should be:
int main()
{
int age, weight;
printf("Enter age and weight: ");
fscanf(stdin, "%d %d", &age, &weight);
printf("\nYou entered: %d %d\n", age, weight);
return 0;
}
Or there is some hidden quirk I'm missing?
There are a few behavior differences in the two approaches. If you use fgets() + sscanf(), you must enter both values on the same line, whereas fscanf() on stdin (or equivalently, scanf()) will read them off different lines if it doesn't find the second value on the first line you entered.
But, probably the most important differences have to do with handling error cases and the mixing of line oriented input and field oriented input.
If you read a line that you're unable to parse with sscanf() after having read it using fgets() your program can simply discard the line and move on. However, fscanf(), when it fails to convert fields, leaves all the input on the stream. So, if you failed to read the input you wanted, you'd have to go and read all the data you want to ignore yourself.
The other subtle gotcha comes in if you want to mix field oriented (ala scanf()) with line oriented (e.g. fgets()) calls in your code. When scanf() converts an int for example, it will leave behind a \n on the input stream (assuming there was one, like from pressing the enter key), which will cause a subsequent call to fgets() to return immediately with only that character in the input. This is a really common issue for new programmers.
So, while you are right that you can just use fscanf() like that, you may be able to avoid some headaches by using fgets() + sscanf().
The problem with only using fscanf() is, mostly, in error management.
Imagine you input "51 years, 85 Kg" to both programs.
The first program fails in the sscanf() and you still have the line to report errors to the user, to try a different parsing alternative, to something;
The second program fails at years, age is usable, weight is unusable.
Remeber to always check the return value of *scanf() for error checking.
fgets(line, sizeof(line), stdin);
if (sscanf(line, "%d%d", &age, &weight) != 2) /* error with input */;
Edit
With your first program, after the error, the input buffer is clear; with the second program the input buffer starts with YEAR...
Recovery in the first case is easy; recovery in the second case has to go through some sort of clearing the input buffer.
There is no difference between fscanf() versus fgets()/sscanf() when:
Input data is well-formed.
Two types of errors occur: I/O and format. fscanf() simultaneously handles these two error types in one function but offers few recovery options. The separate fgets() and sscanf() allow logical separation of I/O issues from format ones and thus better recovery.
Only 1 parsing path with fscanf().
Separating I/O from scanning as with fgets/sscanf allows multiple sscanf() options. Should a given scanning of a buffer not realize the desired results, other sscanf() with different formats are available.
No embedded '\0'.
Rarely does '\0' occurs, but should one occur, sscanf() will not see it as scanning stops with its occurrence, whereas fscanf() continues.
In all cases, check results of all three functions.

Hard-coded string in the format of scanf

I'm trying to match lines with a format like "point %d %d". So I only need to two those two integers, then the "point" is hard-coded in the format string. As I understand reading Linux man pages of scanf, this should work correctly.
The next code, the way I want to use, the first call to scanf works, but the next calls scanf return with an error code and never take more numbers from the stdin (scanf doesn't block waiting for more input from stdin):
for (;;)
{
scanf("point %d %d", &x, &y);
printf("=> point %d %d\n", x, y);
}
In this way, everything work as expected:
int x, y;
char s[10];
for (;;)
{
scanf("%s %d %d", s, &x, &y);
printf("=> point %d %d\n", x, y);
}
Any suggestion about what could I am misunderstanding?
Thanks.
There's still unconsumed data such as end-of-line characters in stdin that make the upcoming scans to stop with a non-match. In the second version this end-of-line data gets consumed by the %s.
I suggest you fgets to a buffer first and then sscanf it. And do check your return values.
My guess is that you are not giving it proper input. For example this input will not work:
4 5
This should work:
point 4 5
You didn't mention the error code, but it is probably saying that you didn't follow the format correctly (i.e. put in point before the numbers).
As a good programming practice you should flush the standard input before taking inputs from user.

Resources