Hard-coded string in the format of scanf - c

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.

Related

Beginner question/problem: Scanf not working as intended in the MacOS terminal

First off I want to mention that I´m completely new to programming, I started my first course this week. This problem seems odd however, here´s my code in C calculating the area of a triangle:
#include <stdio.h>
int main(void) {
double base, height;
printf("Type the base of the triangle\n");
scanf("%lf\n", &base);
printf("Type the height of the triangle\n");
scanf("%lf\n", &height);
printf("Here is the area of the triangle: %.2lf\n", (base * height) / 2);
return 0;
}
It looks alright to me, however in the terminal I get the following result:
The terminal doesn´t "let me" continue to the next scanf unless I type in another number and press return. The value I choose for the height variable doesn´t matter aswell, as the result is (55)/2 instead of (56)/2. It ignores the value '6' and instead uses the second '5' that I typed in under "Type the base of the triangle".
Is anyone familiar with what the problem might be? I´m using MacOS High Sierra, if there are any more details required please let me know, and I appreciate any help I can get!
Let me start by urging you to read this article to know why you shouldn't use scanf and also how you should use it, in case you end up using it anyway:
http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html
Now, putting \n in a scanf format string does not mean to expect a newline, but to read and discard any number of whitespace characters. Since %lf already discards leading whitespace, you don't need explicit whitespace in the format string anyway.
The \n in your case causes scanf to read characters until it finds a non-whitespace character, and it may need to read another line before it can find that non-whitespace character. This is why you are 'forced' to input another number (or any non-whitepace) before the code lets you move on. The fix here is just to use %lf, without the \n.
#include <stdio.h>
int main(void) {
double base, height;
printf("Type the base of the triangle\n");
scanf("%lf", &base);
printf("Type the height of the triangle\n");
scanf("%lf", &height);
printf("Here is the area of the triangle: %.2lf\n", (base * height) / 2);
return 0;
}
However, there are caveats with this approach too, as the article I've linked to above will tell you.
The \n on the format string of scanf tells the the scanf to get Newline character also, but since Newline is part of Whitespace which will be skipped by scanf which means that after matching first number, the scanf look forward for \n or a Non-Whitespace character (since Newline character is ignored, scanf stops when matching 2nd 5).
Let's say the input buffer is 5\n\5\n\6\n, 2 scanf parsing input same buffer(stdin), the first one stopped when reading first input 5, result saved to base , the second one will continue at the point where the first one stopped -> means 2nd input 5 will be read to height therefore 3rd input 6 will be ignored(it can be any Non-Whitespace key to stop the scanner). The result will be (5*5)/2 = 12.5.

Simple test program using sscanf does not work

I was wondering why the following does not work:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int nbytes = 100;
char* string;
string = malloc((sizeof(char) * nbytes) + 1);
int x, y, z;
int args_assigned = 0;
while (args_assigned != 3)
{
printf("Please enter three integers separated by whitespace\n"
scanf("%s", string);
args_assigned = sscanf(string, "%d %d %d", &x, &y, &z);
}
free(string);
printf("Thanks for %d %d %d\n", x, y, z);
return 0;
}
In the original version of this code, the programmer had used getline instead of scanf, but apparently this is no longer a valid function in C99? Please correct me if I am wrong.
Anyway, I suspect the problem is to do with my use of scanf. Is there another function I should be using to provide the string for sscanf to parse? Of course, there could be something far more fundamental that I am missing here...
You ask the user to enter three integers separated by spaces.
You try to read that information with "%s" which stops reading at the first space. This is why you run into problems. You could have found this out by printing what you get from your scanf() call.
Don't forget to check the return value from sscanf().
There is a POSIX function getline() which reads a whole line and tells you how long it is. Alternatively, there is the standard C function fgets() which can be used to read whole lines.
At a pinch, you could use scanf(" %[^\n]", string), but I really wouldn't recommend it; use getline() or fgets().
Be sure to finish this line:
printf("Please enter three integers separated by whitespace\n"
To read a line of input, use fgets().
fgets(string, nbytes + 1, stdin);

Using scanf with multiple data types [duplicate]

This question already exists:
scanf to read multiple data types from one input
Closed 8 years ago.
I am trying to read in an equation in the form of mx+b=y where m, b, and y are integers and x is a character. How do I read in both integers and characters and check that the user inputs the data in that exact form. That is, I somehow need to check that the user inputs a '+' sign an '=' sign and uses the correct variable. eg) I want it to accept mx+b=y but not mX+b=y or another example: accept mx+b=y but not mx-b=y. And I also need it to ignore any additional input after the equation.
I've tried using something like:
scanf(" %d %c %c %d %c %d", &m, &x, &sign, &b, &equal_sign, &y);
Using this format it reads in the first number correctly but skips putting the next character into the variable x and instead puts it in sign.
Sorry for the lengthy wording but I'd appreciate any help and just let me know if I need to clarify anything. Thanks.
I would read the entire line using getline(3) or perhaps fgets(3) then manually parse the buffer containing the line, using strtol(3) with a given end pointer, or sscanf(3) (explicitly testing the returned count, and perhaps using the %n format specifier).
You might want to parse an expression into an AST, e.g. using some recursive descent parsing technique. See also the infix-calc example of GNU bison
If you are sure that your input is exactly of the form a x + b = c (which is unnatural for 3x+-5=8, since you want to type just 3x-5=8) you could use a mix of strtol. See also strncmp(3) and strtok(3)
PS. Follow all the links I am giving you here. They are all relevant!
Get the equation in string format(buffer) and parse this buffer using the sscanf function. By using scanf function there may be a problem of flush kind of things
when you got input prompt , you should try to input one value than tab than another value than tab..and so on .until you entered all values.
scanf(" %d %c %c %d %c %d", &m, &x, &sign, &b, &equal_sign, &y);
first value you entered will be assign to m,
after press tab
second value will be assign to x
press tab..
do this until you entered all values..

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

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

having trouble with a "\n" and scanf

Here is the code
printf("\n");
printf("Enter a integer vaule:");
scanf("%d" , &num3);
printf("You entered: %015d", num3);
printf("Enter a float value:");
scanf("%f", &deci3);
printf("You entered: %15.2f", deci3);
printf("\n");
the output is
Enter a integer vaule:4.4
You entered: 000000000000004
Enter a float value:You entered: 0.40
The problem is this code is not stopping at
printf("Enter a float value:");
and this scanf
scanf("%f", &deci3);
seems to be getting its value from the previous scanf
The %d conversion stops wherever the integer stops, which is a decimal point. If you want to discard the input there, do so explicitly… getc in a loop, fgets, or such. This also allows you to validate the input. The program should probably complain about 4.4.
The scanf function works this way per the specification:
An input item shall be defined as the longest sequence of input bytes (up to any specified maximum field width, which may be measured in characters or bytes dependent on the conversion specifier) which is an initial subsequence of a matching sequence. [Emphasis added.]
In your example, the following C string represents the contents of stdin when the first scanf call requests input: "4.4\n".
For this initial call, your format string consists of a single specifier, %d, which represents an integer. That means that the function will read as many bytes as possible from stdin which satisfy the definition of an integer. In your example, that's just 4, leaving stdin to contain ".4\n" (if this is confusing for you, you might want to check out what an integer is).
The second call to scanf does not request any additional input from the user because stdin already contains ".4\n" as shown above. Using the format string %f attempts to read a floating-point number from the current value of stdin. The number it reads is .4 (per the specification, scanf disregards whitespace like \n in most cases).
To fully answer your question, the problem is not that you're misusing scanf, but rather that there's a mismatch between what you're inputting and how you're expecting scanf to behave.
If you want to guarantee that people can't mess up the input like that, I would recommend using strtol and strtod in conjunction with fgets instead.
This works, but it dont complains if you type 4.4 for the int
#include <stdio.h>
int main() {
char buffer[256];
int i;
float f;
printf("enter an integer : ");
fgets(buffer,256,stdin);
sscanf(buffer, "%d", &i);
printf("you entered : %d\n", i);
printf("enter a float : ");
fgets(buffer,256,stdin);
sscanf(buffer, "%f", &f);
printf("you entered : %f\n", f) ;
return 0;
}
use a fflush(stdin) function after the fist scanf(), this will flush the input buffer.

Resources