scanf doesn't work properly for third time - c

I'm trying to write a simple C program. The input format is like this:
Enter a: <a>
I want to input a, b, c and d but the scanf doesn't work for c and d and the program crashes on that point.
#include <stdio.h>
#include <math.h>
int main(){
int a, b, c, d;
char ch;
printf("Enter a:");
scanf("%c%d%c", &ch, &a, &ch);
printf("Enter b:");
scanf("%c%d%c", &ch, &b, &ch);
printf("Enter c:");
scanf("%c%d%c", &ch, &c, &ch);
printf("Enter d:");
scanf("%c%d%c", &ch, &d, &ch);
double ans;
ans=(a*b/c + c*d/a)/(b*a/c + d*b/a);
ans=fabs(ans);
printf("Formula 1 result = <%lf>", ans);
return 0;
}

There are 3 format conversion specifiers which do not skip leading white space. They are %c (which you're using), %[…] scansets, and %n.
When you type:
Enter a:<1>
Enter b:<2>
The first < satisfies the first %c; the 1 matches the %d, the > matches the second %c, so all is fine so far.
The second lot of input, though, reads the newline from the first line into the first %c, then fails to convert the < to an integer and stops, leaving the < for the next input to process.
The Enter c: prompt is given, but the <2> is processed because it is in the correct format, so the Enter d: prompt is given.
There are multiple ways to fix this, including:
Insert a blank before the first %c in the format strings. This will skip white space, including newlines, and give you the expected behaviour. It is probably the simplest fix.
Read lines and use sscanf() to process them. This is generally the best solution. (Use fgets() to read the line.)
In either case, check that the scanf() family function returns the correct value (3). And use two variables int c1, c2; to read the characters and validate that the user typed what you require.
A bare minimum fixup is:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int a, b, c, d;
char c1, c2;
printf("Enter a: ");
if (scanf(" %c%d%c", &c1, &a, &c2) != 3 || c1 != '<' || c2 != '>')
fprintf(stderr, "Bogus input!\n"), exit(1);
printf("Enter b: ");
if (scanf(" %c%d%c", &c1, &b, &c2) != 3 || c1 != '<' || c2 != '>')
fprintf(stderr, "Bogus input!\n"), exit(1);
printf("Enter c: ");
if (scanf(" %c%d%c", &c1, &c, &c2) != 3 || c1 != '<' || c2 != '>')
fprintf(stderr, "Bogus input!\n"), exit(1);
printf("Enter d: ");
if (scanf(" %c%d%c", &c1, &d, &c2) != 3 || c1 != '<' || c2 != '>')
fprintf(stderr, "Bogus input!\n"), exit(1);
double ans;
ans=(a*b/c + c*d/a)/(b*a/c + d*b/a);
ans=fabs(ans);
printf("Formula 1 result = <%lf>\n", ans);
return 0;
}
I'm being lazy with the comma operators after the if statement. It would be better, though, to use a function to manage the inputs:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
static void get_number(int *var, const char *name)
{
char c1, c2;
printf("Enter %s: ", name);
if (scanf(" %c%d%c", &c1, var, &c2) != 3 || c1 != '<' || c2 != '>')
{
fprintf(stderr, "Bogus input!\n");
exit(1);
}
}
int main(void)
{
int a, b, c, d;
get_number(&a, "a");
get_number(&b, "b");
get_number(&c, "c");
get_number(&d, "d");
double ans;
ans=(a*b/c + c*d/a)/(b*a/c + d*b/a);
ans=fabs(ans);
printf("Formula 1 result = <%lf>\n", ans);
return 0;
}
And better still to use:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
static int get_number(const char *name)
{
char buffer[4096];
printf("Enter %s: ", name);
if (fgets(buffer, sizeof(buffer), stdin) == 0)
{
fprintf(stderr, "EOF or error on input\n");
exit(1);
}
char c1, c2;
int val;
if (sscanf(buffer, " %c%d%c", &c1, &val, &c2) != 3 || c1 != '<' || c2 != '>')
{
/* buffer contains a newline unless you typed more than 4095 characters before the newline */
fprintf(stderr, "Bogus input (does not match <number>): %s", buffer);
exit(1);
}
return val;
}
int main(void)
{
int a = get_number("a");
int b = get_number("b");
int c = get_number("c");
int d = get_number("d");
double ans = fabs((a*b/c + c*d/a) / (b*a/c + d*b/a));
printf("Inputs: a = %d, b = %d, c = %d, d = %d\n", a, b, c, d);
printf("Formula 1 result = <%lf>\n", ans);
return 0;
}
Note how the code uses fgets() plus sscanf() which means that the error message can tell the user what they entered that was not what was expected. It also uses the function to return the value, leading to the simpler code shown. And the output includes the input values for inspection. That may not be needed for your submission system, but it surely helps you while you're developing the code.
You can work on the upgrade to process double values as inputs; it isn't hard.

double ans;
ans=(a*b/c + c*d/a)/(b*a/c + d*b/a);
The C language doesn't take into account what you do with a result when it determines its type. So the fact that you assign the results of this operation to a double don't have any effect on the way the result is computed, it just converts the integer result to a double. When you divide integers by integers, you get integer division.
You could do something like this:
ans=(a*1.0*b/c + c*1.0*d/a)/(b*1.0*a/c + d*1.0*b/a);
The multiplication by a non-integer forces non-integer multiplication, addition, and division to be used.

Related

How to make scanf stop reading from input based on the first char?

I am stuck with scanf()
Can somebody help me please and tell me how can I read the first character in scanf() and based on that character decide whether I want to read 1 or 2 or 3 inputs:
For example :
scanf( char , int int int) if character
S , how do I make it stop after input :
S 45
For this kind of problem, and to easier error recovery in general, you should read one line of input at a time with fgets() and use sscanf() to parse the line.
Here is an example:
#include <stdio.h>
int main() {
char line[128];
printf("Enter letter and values:\n");
if (fgets(line, sizeof line, stdin)) {
if (*line == 'A') {
int a, b, c;
if (sscanf(line, "A %d %d %d", &a, &b, &c) == 3) {
printf("A code, a=%d, b=%d, c=%d\n", a, b, c);
} else {
printf("A code requires 3 integers\n");
}
} else
if (*line == 'S') {
int a;
if (sscanf(line, "S %d", &a) == 1) {
printf("S code, a=%d\n", a);
} else {
printf("S code requires 1 integer\n");
}
} else
{
/* handle other input codes... */
}
}
return 0;
}

Why does this code produce 1 on adding characters in C?

I was trying to restrict user input from alphabets (Eg: repeat input until correct input is provided ) , in order to get only numbers to be added. Somehow, instead of able to do so, I was able to add alphabets, but with out being '1'
It increments 1 if a number with a character is given.
#include<stdio.h>
int main() {
int x,y;
while(1)
{
printf("Enter a number > ");
if(scanf("%d%d",&x,&y) != 1){
printf("%d",x+y);
break;
}
}
return 0;
}
What could be the reason behind it?
scanf() returns the number of successful conversions it has performed for the input given.
With
scanf("%d%d", &x, &y)
you ask for two integers so scanf() will return 2 if it was successful. Your code however checks for != 1 which will also be true if scanf() returns 0 becuause you entered "a b" and no conversation could be performed.
If not all conversions were successful, all characters not being part of a successful conversion remain in stdin and the next scanf() will try to interpret them again and fail. To prevent that from happening you have to "clear" them:
#include <stdio.h>
int main()
{
while(1)
{
printf("Enter two numbers: ");
int x, y; // define variables as close to where they're used as possible
if (scanf("%d%d", &x, &y) == 2) {
printf("%d\n", x + y);
break;
}
else {
int ch; // discard all characters until EOF or a newline:
while ((ch = getchar()) != EOF && ch != '\n');
}
}
return 0;
}
The more ideomatic way:
int x, y;
while (printf("Enter two numbers: "),
scanf("%d%d", &x, &y) != 2)
{
fputs("Input error :(\n\n", stderr);
int ch;
while ((ch = getchar()) != EOF && ch != '\n');
}
printf("%d\n", x + y);

Scanf returns 0 without waiting for input

I have never programmed in C and today I have to write small code. Program is very easy - I want to add two integers.
But when I'm trying to check if given input is a number and first scanf returns 0, the second one returns 0 too without waiting for input.
Code:
int main()
{
int a = 0;
int b = 0;
printf("Number a:\n");
if (scanf("%d", &a) != 1)
{
printf("Not a number. a=0!\n");
a = 0;
}
printf("Number b:\n");
if (scanf("%d", &b) != 1)
{
printf("Not a number. b=0!\n");
b = 0;
}
printf("%d\n", a+b);
return 0;
}
The input that failed to convert to a number for the first fscanf() is still pending in standard input's buffer and causes the second fscanf() to fail as well. Try discarding offending input and re-prompting the user:
#include <stdio.h>
int main(void) {
int a = 0;
int b = 0;
int c;
printf("Number a:\n");
while (scanf("%d", &a) != 1) {
printf("Not a number, try again:\n");
while ((c = getchar()) != EOF && c != '\n')
continue;
if (c == EOF)
exit(1);
}
printf("Number b:\n");
while (scanf("%d", &b) != 1) {
printf("Not a number, try again:\n");
while ((c = getchar()) != EOF && c != '\n')
continue;
if (c == EOF)
exit(1);
}
printf("%d\n", a + b);
return 0;
}
Factorizing the code with a utility function makes it much clearer:
#include <stdio.h>
int get_number(const char *prompt, int *valp) {
printf("%s:\n", prompt);
while (scanf("%d", valp) != 1) {
printf("Not a number, try again:\n");
while ((c = getchar()) != EOF && c != '\n')
continue;
if (c == EOF)
return 0;
}
return 1;
}
int main(void) {
int a, b;
if (!get_number("Number a", &a) || !get_number("Number b", &b)) {
return 1;
}
printf("%d\n", a + b);
return 0;
}
That is because, once the first scanf() failed, it is probably because of matching failure, and the input which caused the matching failure, remains inside the input buffer, waiting to be consumed by next call.
Thus, the next call to scanf() also try to consume the same invalid input residing in the input buffer immediately, without waiting for the explicit external user input as the input buffer is not empty.
Solution: After the first input fails for scanf(), you have to clean up the input buffer, for a trivial example, something like while (getchar() != '\n'); should do the job.
This happens if there is any input from the previous entry, can take that, and skip input from the user. In the next scanf also It takes the new line which is left from the last scanf statement and automatically consumes it. That's what happening in your code.
You can clear previous input in stdin stream by using fflush(stdin); before starting your program.
This can also be solved by leaving a space before % i.e scanf(" %d",&n);,Here leaving whitespace ensures that the previous new line is ignored.
Or we can use getc(stdin) before calling any scanf statement, Sometimes it helps very much.
int main()
{
int a = 0;
int b = 0;
printf("Number a:");
//getc(stdin);
if (scanf(" %d", &a) != 1)
{
printf("Not a number. a=0!\n");
a = 0;
}
printf("Number b:\n");
//getc(stdin);
if (scanf(" %d", &b) != 1)
{
printf("Not a number. b=0!\n");
b = 0;
}
printf("%d\n", a+b);
return 0;
}
It's because of input and output aren't synchronized in C. The program can output some lines after user's input while the input hasn't been read. Try to run this code:
char token;
scanf("%c", &token);
printf("%c\n", token);
printf("line 1\n");
scanf("%c", &token);
printf("%c\n", token);
printf("line 2\n");
scanf("%c", &token);
printf("%c\n", token);
printf("line 3\n");
And input abc in one line.
You can imagine this like there are two separated consoles, one for input and another for output.
For example you want to input asd for a and 3 for b. In this case, the first scanf won't find any number and will return 0. But it also won't read anything from the input. Because of this, the second scanf will see asd too.
To clear the input if a isn't a number, you should input all remaining chars in the line until '\n' (look at the #Sourav's solution)
You could do the same thing using strings without problems with scanf. Just take the user input as string and convert it to integer. Then convert the string back to integer to check whether they are the same. If they are the same, treat a and b as integers, if not, do what you do (You will need to include string.h). Here is the working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int a;
int b;
char str1[100];
char str2[100];
printf("Number a:\n");
scanf("%s", &str1); //take input as a string
a = atoi(str1); //convert string to integer
snprintf(str2, 100, "%d", a); //convert integer back to string
//if the integer converted to string is not the same as the string converted to integer
if (strcmp(str1, str2)!= 0)
{
printf("Not a number. a=0!\n");
a = 0;
}
printf("Number b:\n");
scanf("%s", &str1);
b = atoi(str1);
snprintf(str2, 100, "%d", b);
if (strcmp(str1, str2)!= 0)
{
printf("Not a number. b=0!\n");
b = 0;
}
printf("%d\n", a+b);
return(0);
}

for-loop stuck in endless loop [duplicate]

I have never programmed in C and today I have to write small code. Program is very easy - I want to add two integers.
But when I'm trying to check if given input is a number and first scanf returns 0, the second one returns 0 too without waiting for input.
Code:
int main()
{
int a = 0;
int b = 0;
printf("Number a:\n");
if (scanf("%d", &a) != 1)
{
printf("Not a number. a=0!\n");
a = 0;
}
printf("Number b:\n");
if (scanf("%d", &b) != 1)
{
printf("Not a number. b=0!\n");
b = 0;
}
printf("%d\n", a+b);
return 0;
}
The input that failed to convert to a number for the first fscanf() is still pending in standard input's buffer and causes the second fscanf() to fail as well. Try discarding offending input and re-prompting the user:
#include <stdio.h>
int main(void) {
int a = 0;
int b = 0;
int c;
printf("Number a:\n");
while (scanf("%d", &a) != 1) {
printf("Not a number, try again:\n");
while ((c = getchar()) != EOF && c != '\n')
continue;
if (c == EOF)
exit(1);
}
printf("Number b:\n");
while (scanf("%d", &b) != 1) {
printf("Not a number, try again:\n");
while ((c = getchar()) != EOF && c != '\n')
continue;
if (c == EOF)
exit(1);
}
printf("%d\n", a + b);
return 0;
}
Factorizing the code with a utility function makes it much clearer:
#include <stdio.h>
int get_number(const char *prompt, int *valp) {
printf("%s:\n", prompt);
while (scanf("%d", valp) != 1) {
printf("Not a number, try again:\n");
while ((c = getchar()) != EOF && c != '\n')
continue;
if (c == EOF)
return 0;
}
return 1;
}
int main(void) {
int a, b;
if (!get_number("Number a", &a) || !get_number("Number b", &b)) {
return 1;
}
printf("%d\n", a + b);
return 0;
}
That is because, once the first scanf() failed, it is probably because of matching failure, and the input which caused the matching failure, remains inside the input buffer, waiting to be consumed by next call.
Thus, the next call to scanf() also try to consume the same invalid input residing in the input buffer immediately, without waiting for the explicit external user input as the input buffer is not empty.
Solution: After the first input fails for scanf(), you have to clean up the input buffer, for a trivial example, something like while (getchar() != '\n'); should do the job.
This happens if there is any input from the previous entry, can take that, and skip input from the user. In the next scanf also It takes the new line which is left from the last scanf statement and automatically consumes it. That's what happening in your code.
You can clear previous input in stdin stream by using fflush(stdin); before starting your program.
This can also be solved by leaving a space before % i.e scanf(" %d",&n);,Here leaving whitespace ensures that the previous new line is ignored.
Or we can use getc(stdin) before calling any scanf statement, Sometimes it helps very much.
int main()
{
int a = 0;
int b = 0;
printf("Number a:");
//getc(stdin);
if (scanf(" %d", &a) != 1)
{
printf("Not a number. a=0!\n");
a = 0;
}
printf("Number b:\n");
//getc(stdin);
if (scanf(" %d", &b) != 1)
{
printf("Not a number. b=0!\n");
b = 0;
}
printf("%d\n", a+b);
return 0;
}
It's because of input and output aren't synchronized in C. The program can output some lines after user's input while the input hasn't been read. Try to run this code:
char token;
scanf("%c", &token);
printf("%c\n", token);
printf("line 1\n");
scanf("%c", &token);
printf("%c\n", token);
printf("line 2\n");
scanf("%c", &token);
printf("%c\n", token);
printf("line 3\n");
And input abc in one line.
You can imagine this like there are two separated consoles, one for input and another for output.
For example you want to input asd for a and 3 for b. In this case, the first scanf won't find any number and will return 0. But it also won't read anything from the input. Because of this, the second scanf will see asd too.
To clear the input if a isn't a number, you should input all remaining chars in the line until '\n' (look at the #Sourav's solution)
You could do the same thing using strings without problems with scanf. Just take the user input as string and convert it to integer. Then convert the string back to integer to check whether they are the same. If they are the same, treat a and b as integers, if not, do what you do (You will need to include string.h). Here is the working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int a;
int b;
char str1[100];
char str2[100];
printf("Number a:\n");
scanf("%s", &str1); //take input as a string
a = atoi(str1); //convert string to integer
snprintf(str2, 100, "%d", a); //convert integer back to string
//if the integer converted to string is not the same as the string converted to integer
if (strcmp(str1, str2)!= 0)
{
printf("Not a number. a=0!\n");
a = 0;
}
printf("Number b:\n");
scanf("%s", &str1);
b = atoi(str1);
snprintf(str2, 100, "%d", b);
if (strcmp(str1, str2)!= 0)
{
printf("Not a number. b=0!\n");
b = 0;
}
printf("%d\n", a+b);
return(0);
}

scanning a string to hex char array

Here is my sample code :
char a;
char str [20];
unsigned char b[8] ;
unsigned char c[8];
int argsread;
int i;
init_8051();
while(1)
{
printf("\n enter a 64 bit operation \n");
argsread = scanf("%s", str);
sscanf(str, "0x%x%c0x%x", b, &a, c);
printf("\n %d arguments read \n",argsread);
for(i=0;i<8;i++)
{
printf("\n %#x %c %#x\n",b[i],a,c[i]);
}
}
}
The problem here is that when i enter for example in the terminal the following input :
0x1234567890abcdef+0x1234567890abcdef
this leads to an error where output for char array is totally wrong and most of the numbers are traced into a , which should have been the plus sign , am ai doing something fundamentally wrong ?
Update:
I changed my code to the following :
while(1)
{
printf("\n enter a 64 bit operation \n");
argsread = scanf("%s", str);
sscanf(str, "0x%s%c0x%s", b, &a, c);
printf("\n %d arguments read \n",argsread);
printf("\n %s \n",b);
}
and i increased size of str to 30 the problem is the output of the program is :
1 arguments read
abcdef+0xabcdef
so the value of b instead of being just abcdef it the the whole string!!
Update2:
Found this code which works perfect but i wanted to use scanf instead of cin here is the code
:`#include <iostream>
using namespace std;
int main()
{
float a, b, result;
char oper, clear;
cout << "Please enter an equation: i.e 5+5 " << endl;
for (;;) {
cin >> a;
cin >> oper;
cin >> b;
if (oper == '+')
result = a + b;
else if (oper == '-')
result = a - b;
else if (oper == '*')
result = a * b;
else if (oper == '/')
result = a / b;
cout << "= " << result << endl << endl;
cin.clear();
cin.ignore();
}
} `
User input and error handling much easier if code starts with fgets().
Then use sscanf(), strtol(), etc. to parse.
printf("\n enter a 64 bit operation \n");
char buf[100];
if (fgets(buf, sizeof buf, stdin) == NULL) Handle_IOErrororEOF();
char a;
char b[17]; // use right size arrays
char c[17];
// use width of 16 and %[]
if (sscanf(buf, " 0x%16[0-9abcdef] %c 0x%16[0-9abcdef]", b, &a, c) != 3) {
Handle_Bad_Input();
}
OTOH, just use an integer format specifier that allows hex input "%x" or "%i"
unsigned long long b,c;
if (sscanf(buf, "%lli %c%lli", &b, &a, &c) != 3) {
Handle_Bad_Input();
}
Why char str [20]; scanf("%s", str); has trouble:
"%s" does 3 things:
1) scans, but does not save, all preceding (0 or more) white-space (' ', '\t', '\n ', etc.).
2) scans and saves all non-white-space.
3) Finally reaching a white-space. it stops scanning and puts that white-space back into stdin.
The "%s" specifier lacks a width, like "%19s", so it can easily overfill str
sscanf(str, "0x%s%c0x%s", b, &a, c); has trouble too.
Input has no white-space between the end of the first number and the '+', so "%s" continues scanning. Code does not check the return value from sscanf() and then uses a, b, c. So a, b, c may not be properly scanned nor initialized - leading to potential undefined behavior .
You are reading a string using scanf and storing it in an integer. I think that is what is causing you the problem.
Also, from the MAN Page
AME
scanf, fscanf, sscanf, vscanf, vsscanf, vfscanf
...
RETURN VALUE
These functions return the number of input items successfully matched
and assigned, which can be fewer than provided for, or even zero in the
event of an early matching failure.
The value EOF is returned if the end of input is reached before either
the first successful conversion or a matching failure occurs. EOF is
also returned if a read error occurs, in which case the error indicator
for the stream (see ferror(3)) is set, and errno is set indicate the
error.
I think you missplaced the assignment, if you want to know how many arguments matched, then change this
argsread = scanf("%s", str);
sscanf(str, "0x%x%c0x%x", b, &a, c);
to this
scanf("%s", str);
argsread = sscanf(str, "%x%c%x", b, &a, c);
According to your comments, you should change some other things, may be this code will work
char a;
char str [64];
unsigned int b;
unsigned int c;
char B[11];
char C[11];
int argsread;
while(1)
{
printf("\n enter a 64 bit operation \n");
scanf("%s", str);
argsread = sscanf(str, "0x%x%c0x%x", &b, &a, &c);
if (argsread == 3)
{
printf("\n %d arguments read\n", argsread);
snprintf(B, sizeof(B), "0x%08X", b);
snprintf(C, sizeof(B), "0x%08X", c);
printf("\n %s%c%s\n", B, a, C);
}
}
return 0;

Resources