How to read an unknown quantity of integers from console? - c

I have entries like these:
0 5 260
1 0 -598
1 5 1508
2 1 -1170
I don't know previously how many (console) inputs I'll get, so I have to read until there are no entries left.
I started with a code like this:
int a, b, c;
while(scanf("%d %d %d", &a, &b, &c)!=EOF){
// do stuff here
}
But it never stops asking for new input.
Then, I saw people in other threads suggesting this:
int a, b, c;
while(scanf("%d %d %d", &a, &b, &c)==1){
// do stuff here
}
In this case, it doesn't even enter the while.
Does anyone know what I'm doing wrong?

An approach: Continue asking for input until the input is closed (EOF) or some problem is encountered. (Invalid line of input)
The below uses fgets() to read a line.
Then, " %n" to detect where scanning stopped. If scanning does not reach %n, n will still have the value of 0. Otherwise it gets the offset in buffer where scanning stopped, hopefully it was at the null character '\0'.
char buffer[100];
while (fgets(buffer, sizeof buffer, stdin)) {
int n = 0;
sscanf(buffer, "%d%d%d %n", &a, &b, &c, &n);
if (n == 0) {
fprintf(stderr, "3 int were not entered\n");
break;
}
if (buffer[n] != 0) {
fprintf(stderr, "Extra input detected.\n");
break;
}
// do stuff here with a,b,c
}
There are many approaches to solve this issue.

while(scanf("%d %d %d", &a, &b, &c)==1)
means that "if scanf() successfully read just one value, proceed in the loop."
Therefore, if you enter something like 0 junk, the scanf() read just 1 data and will enter the loop once.
Try using
while(scanf("%d %d %d", &a, &b, &c)==3)
to have it enter the loop when scanf() successfully read three values, which is what expected.

Related

scanf with variable arguments (C lang)

My Input is as below.
3 8 9 3
4 2 4 0 3
5 1 5 9 3 1
0
1 5
As you can see, the first number of each line means the number of how many inputs left in the line.
How can I get all input via scanf?
Or please let me know something new.
As mentioned in the comments, the problem with scanf() is (among other things) the way it handles the newline character. However, the sscanf() function (reading from a string) doesn't have this issue! So, depending on exactly what you're trying to achieve, maybe something like the following code will help:
#include <stdio.h>
int main()
{
int a[5], n = 0, given;
char buffer[200];
while (n >= 0) {
printf("\nEnter n and a list of numbers: ");
fgets(buffer, 200, stdin);
printf("Input was: %s", buffer);
n = -1;
given = sscanf(buffer, "%d %d %d %d %d %d", &n, &a[0], &a[1], &a[2], &a[3], &a[4]);
if ((given < 1) || (given != n + 1)) printf("Invalid input!\n");
}
return 0;
}
I'm not saying it's an ideal solution, or even that you could use it, but it may give you some clues as to where to go next.
Let me know how you find it.

program to detect whether only integer has been given or not goes into infinite loop

// program to detect whether only integer has been given or not
int main() {
int a, b, s;
printf("Enter two proper number\n");
BEGIN:
s = scanf("%d %d", &a, &b); //storing the scanf return value in s
if (s != 2) {
printf("enter proper value\n");
goto BEGIN;
}
printf("The values are %d and %d ", a, b);
}
This program to detect whether only integer has been given or not goes into infinite loop when invalid data is entered instead of asking for new values
why doesn't the goto work here?
Note that when scanf gets bad input (for example you enter cat dog) that input remains in the input buffer until you take steps to clear it out. So the loop keeps repeating and rejecting the same input which is still there.
It is simpler to use fgets and sscanf and if the scan fails, you just forget the input string and get another.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int a, b;
char str[42];
do {
printf("Enter 2 numeric values\n");
if(fgets(str, sizeof str, stdin) == NULL) {
exit(1);
}
} while(sscanf(str, "%d%d", &a, &b) != 2);
printf("Numbers are %d and %d\n", a, b);
}
Program session:
Enter 2 numeric values
cat dog
Enter 2 numeric values
cat 43
Enter 2 numeric values
42 dog
Enter 2 numeric values
42 43
Numbers are 42 and 43
Note that goto is poor practice in C and should be used only where there is no other way of constructing the code — which there usually is.
There are multiple reasons scanf() can return a value different from 2:
there is pending input that cannot be converted according to the conversion specification. For example if there is an A pending in the input stream, the %d conversion fails and the A stays in the input stream. Your code just keeps trying this conversion and will never stop. You should read and discard the offending input before re-trying.
the input stream has had a read error or hit the end of file. If at least one conversion succeeded, the number of successful conversions is returned, otherwise EOF is returned. If EOF is returned, there is no point trying again since no more input will be available.
Note also that it is considered bad style to use goto for constructions that are better expressed with flow control statements such as while and for.
Here is a corrected version:
#include <stdio.h>
// program to detect whether only integer has been given or not
int main() {
int a, b, s, c;
printf("Enter two proper numbers: ");
for (;;) {
s = scanf("%d%d", &a, &b); //storing the scanf return value in s
if (s == 2) // conversions successful
break;
if (s == EOF) {
printf("unexpected end of file\n");
return 1;
}
/* discard the rest of the input line */
while ((c = getchar()) != EOF && c != '\n')
continue;
printf("Invalid input. Try again: ");
}
printf("The values are %d and %d\n", a, b);
return 0;
}
scanf returns the number of characters. As a result, s will be equal to the number of characters you have written is 2, then your loop will stop. The reason this runs infinitely many times is that the number of characters you have entered differed from 2. Print s to see what value it holds and you will get more information.

Why does this while-loop in C not work?

Ignoring the fact that negative numbers would not work here, why do positive integers create a infinite loop? I tried many combinations, as simple as a = 20 and b = 4, but every single one creates a infinite loop. What am I doing wrong or not seeing here?
#include <stdio.h>
int mdc(int a, int b) {
while (a != b) {
if (a > b)
a = a - b;
else b = b - a;
}
return a;
}
int main() {
int a, b;
printf("Valores mdc: \n");
scanf("%d %d\n", &a, &b);
printf("%d\n", mdc(a,b));
return 0;
}
Not an infinite loop for the given input:-
The thing is you have used \n in the scanf as a result unless you enter some non-whitespace character - it waits for it.
What did the '\n' do?
From standard explaining the why part - C11 N1570 §7.21.6.2¶5
A directive composed of white-space character(s) is executed by reading input up to the first non-white-space character (which remains unread), or until no more characters can be read. The directive never fails.
How to give input then?
So it will work if you do this:-
>>> 20 4 Enter
<Somenonwhitespace> Enter
Better solution:
Even better suggestion would be to use
scanf("%d%d", &a, &b);
You don't need to specify the space as you did - %d directive skips over the white space characters.
Code wise
if(scanf("%d%d", &a, &b)!=2){
fprintf(stderr,"Error in input\n");
exit(EXIT_FAILURE);
}
If you were to step the code in a debugger you would discover that the while loop is never even entered. It is not a problem of an infinite while-loop. Rather that scanf() never returns.
Change:
scanf("%d %d\n", &a, &b);
to
scanf("%d %d", &a, &b);
The line scanf("%d %d\n", &a, &b); should be scanf("%d %d", &a, &b); no \n.

How to read lines with different formats

I have an input file with the following form
i 176064 Patterson Denise 8.58 11 DEN 15788
q 188464
ra 148702 167443
a 73131
d 163464
f 6.00
ct 73131 PHY
b 3
p 15703
pe
m 144626 6.51 8
e
The first character in each line[i,q,ra,a...] represents an code to a function , while the rest are values that I must store into variables,depending on that code. What's the best way to achieve this ? I have been thinking about using fscanf but each line does not have a specific format, the format itself depends on the code [i,q,ra,a,b..]
To read a line, use fgets()
char buffer[100];
while (fgets, buffer, sizeof buffer, istream) != NULL) {
Then scan the line against the various formats, each ending with " %n". "%n" records the scan position, if it got that far. Additional tests could check for extraneous extras character starting at n.
int num1, num2, num3;
char last[sizeof buf];
char first[sizeof buf];
char code[sizeof buf];
double rate;
int n = 0;
// v..v..v..v...v..v..v spaces optional here
sscanf(buffer, "i %d %s %s %lf %d %s %d %n",
&num1, last, first, &rate, &num2, code, &num3, &n);
if (n) {
Handle_i();
continue;
}
sscanf(buffer, "q %d %n", &num1, &n);
if (n) {
Handle_q();
continue;
}
sscanf(buffer, "ra %d %n", &num1, &num2, &n);
if (n) {
Handle_ra();
continue;
}
sscanf(buffer, "e %n", &n);
if (n) {
Handle_e();
continue;
}
...
fail();
}
As each format begins with a unique letter pattern, the sscanf() will quickly exit on mis-match.
Alternative, code could parse out the initial letters for a slightly more efficient decision tree. Suspect profiling will show little performance difference.
As with any complex format, consider how one would maintain the code and it is bound to evolve.

Validate Input to a C Program

i have a c program in which i am accepting 2 numbers as input.
How do i validate if input entered is numbers only and not characters.
void main()
{
int a,b;
printf("Enter two numbers :");
scanf("%d%d",&a,&b);
printf("Number 1 is : %d \n Number 2 is : %d",a,b);
}
[Edit] Added Sample Code
Besides the other interesting suggestions (especially the one with scanf), you might also want to use the isdigit function:
The isdigit() function shall test
whether c is a character of class
digit in the program's current locale
note that this function examines only ONE char, not an entire bunch of them.
It is always good practice to resort to already-built functions; there are intricacies you might not be aware of even in the simplest task, and this will make you a good programmer overall.
Of course, in due time you might want to look at how that function works to get a good grasp of the underlying logic.
scanf returns the number of items that it has successfully scanned. If you asked for two integers with %d%d, and scanf returns 2, then it successfully scanned both numbers. Any number less than two indicates that scanf was unable to scan two numbers.
int main()
{
int a,b;
int result;
printf("Enter two numbers :");
result = scanf("%d%d",&a,&b);
if (result == 2)
{
printf("Number 1 is : %d \n Number 2 is : %d",a,b);
}
else if (result == 1)
{
// scanf only managed to scan something into "a", but not "b"
printf("Number 1 is : %d \n Number 2 is invalid.\n", a);
}
else if (result == 0)
{
// scanf could not scan any number at all, both "a" and "b" are invalid.
printf("scanf was not able to scan the input for numbers.");
}
}
One other value that scanf may return is EOF. It may return this if there is an error reading from the stream.
Also note that main returns int, but you have it declared with void return.
Read user line of text input as a string. This greatly simplifies error handling.
int a = 0, b = 0;
char buf[100];
for (;;) {
printf("Enter two integers :");
if (fgets(buf, sizeof buf, stdin) == NULL) {
printf("Input closed\n");
break;
}
Then test the string for 2 ints with no following junk. Use sscanf() (simple) , strtol() (more robust), etc.
int n; // %n records where scanning stopped
if (sscanf(buf, "%d%d %n", &a, &b, &n) == 2 && buf[n] == '\0') {
printf("Number 1 is : %d \n Number 2 is : %d", a, b);
break;
}
printf("<%s> is not 2 integers. Try again\n", buf);
}
More advanced code uses strtol() to validate and also detect excessively long lines of input.

Resources