How to exit a scanf loop with newline character. Currently loops indefinitely - c

I am trying to get: while(scanf("%c %c %d\n", &a, &b, &c) && (a!='\n')) to exit once a line is blank, eg the following:
a b 12
q w 4
g u 80
(exit)
Code:
while(scanf("%c %c %d\n", &a, &b, &c) && (a != '\n'))

To read a line, use fgets(). Then, if successful, parse the input string for '\n', expected a,b,c, or anything else.
// c ' ' c ' ' d \n \0
#define LINE_EXPECTED_SIZE (1 + 1 + 1 + 1 + 11 + 1 + 1)
char buf[LINE_EXPECTED_SIZE * 2]; // let us be generous with size.
while (fgets(buf, sizeof buf, stdin) && buf[0] != '\n') {
char a,b;
int c;
if (sscanf(buf, "%c %c %d", &a, &b, &c) != 3) {
// Note unexpected input
fprintf(stderr, "Unexpected bad input '%s'\n", buf);
break;
}
printf("a:'%c', b:'%c', c%d\n", a,b,c);
}
"\n" is rarely correct at the end of a scan() format. #Jonathan Leffler.
The above uses sscanf(...) != 3 to detect if 3 specifiers were matched. This will not detect if extra text was on the line. An advanced approach uses " %n" to scan optional following white-space and then note the scan offset at that point.
// if (sscanf(buf, "%c %c %d", &a, &b, &c) != 3) {
int n = 0;
sscanf(buf, "%c %c %d %n", &a, &b, &c, &n);
if (n == 0 || buf[n] != '\0') {
// if scanning did not reach %n or extra text followed ...

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

Unable to understand - reading characters from files in C

I have just started learning file handling in C, and wondered if I could perform mathematical calculations by reading input from a file, here is the code for just reading the characters and displaying on the console :
int main(void)
{
FILE *p;
char a, b, c, ch;
p = fopen("numbers.txt", "a+");
while((ch = getc(p)) != EOF)
{
fscanf(p, "%c %c %c\n", &a, &b, &c);
printf("%c %c %c\n", a, b, c);
}
fclose(p);
return 0;
}
numbers.txt contains (with a space before each character) :
2 + 3
5 + 6
6 + 7
output obtained is :
2 + 3
+ 6
+ 7
I am unable to understand why first line output is as expected but second and third line have missing character, even though new line is given after each expression in numbers.txt.
An additional character is being scanned at the beginning of each iteration of your while loop
while((ch = getc(p)) != EOF)
Try making the fscanf() statement as the condition for your while loop and check for its return value. According to cplusplus.com:
On success, the function returns the number of items of the argument
list successfully filled. This count can match the expected number of
items or be less (even zero) due to a matching failure, a reading
error, or the reach of the end-of-file.
If a reading error happens or the end-of-file is reached while
reading, the proper indicator is set (feof or ferror). And, if either
happens before any data could be successfully read, EOF is returned.
So try changing your while condition to anyone of the following:
while (fscanf(p, " %c %c %c", &a, &b, &c) != EOF)
or
while (fscanf(p, " %c %c %c", &a, &b, &c) == 3)
Using whitespace in the scanf format specifier, like you do with \n, matches any amount of whitespace. The \n and the leading space on the next line are consumed, causing getc to remove the first digit instead of the leading space.
I’d skip getc entirely, as #BLUEPIXY suggested:
while (fscanf(p, " %c %c %c", &a, &b, &c) == 3) {
printf("%c %c %c\n", a, b, c);
}

scanf doesn't work properly for third time

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.

How to use fscanf, care about endofline?

I want to read int from a file
The first line is composed of 1 int and the second of 2
ie
1
2 3
if i do
fscanf(FILE, "%d \n %d %d", &a, &b, &c);
I obtain correctly the 3 numbers
but if i put all the numbers on the same line in the file
ie 1 2 3
I obtain the same result (and that's not what i want)
I want to know : How to force the user to go to a new line in his file ?
Edit :
As it seems unclear to some (i'm sorry for that) i want that the file
1
2 3
Produce the result :
a = 1
b = 2
c = 3
And the file
1 2 3
produce either an error or
a = 1
b = 0
c = 0
You need to read each line into a char buffer using fgets and parse each line with its own sscanf. You can use an extra %s on the end of the format string (and an extra pointer argument to a dummy variable of type char *) to detect whether the line contains extra stuff after the fields you're looking for.
fscanf(FILE, "%d", ...); first scans and discard white space before scanning for int characters. In scanning white-space, both ' ' and '\n' are treated the same, so using '%d' loses the end-of-line.
fscanf(FILE, "\n", ...); and fscanf(FILE, " ", ...); do the same thing: scan and discard any white space. Using "\n" does not scan only for '\n'.
Code could use fscanf(FILE, "%d%*1[\n]%d %d", &a, &b, &c) == 3, to find a '\n' after a, but additional '\n' could be lurking in other places.
The only way using scanf() family to detect a '\n' involves using '%c' or '%[]' or '%n'. It is easier to use fgets() and then parse with sscanf() or strtol().
int Read1and2int(FILE *stream, int *a, int *b, int *c) {
char buf[100];
int n;
if (fgets(buf, sizeof buf, stream) == NULL) return EOF;
int count = sscanf(buf,"%d %n", a, &n);
// Non-numeric or extra data
if (count != 1 || buf[n]) return 0;
if (fgets(buf, sizeof buf, stream) == NULL) return 1;
count = sscanf(buf,"%d%d %n", b, c, &n);
// Non-numeric or extra data
if (count != 2 || buf[n]) return 1;
return 3;
}

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