I have this file:
0 -> 1:50 2:30 3:10
1 ->
2 -> 0:10 3:20
3 -> 1:20 2:10 3:30
And I want to extract all the numbers from the file with this code:
int a, b, c;
while (fscanf(fp, "%d ->", &a) == 1) {
printf("%d ->", a);
while (fscanf(fp, " %d:%d", &b, &c) == 2) {
printf(" %d:%d", b, c);
}
printf("\n");
}
The idea is that on the first loop it will scan the first number followed by space followed by -> and then the inner loop will scan the following sequence of " %d:%d" until the end of line which will then make the outer loop return 1 because it could successfully read "%d ->".
Ouput of code:
0 -> 1:50 2:30 3:10
It seems like it doesn't work as expected, and the outer while loop exits when it tried to read the number 1 from the second line(but it should?). I just find this weird because I've done something similar recently and it was working fine.
After removing the loops and replacing with this code I get the correct results so it had something to do with my loops:
fscanf(fp, "%d ->", &a);
fscanf(fp, " %d:%d", &b, &c);
fscanf(fp, " %d:%d", &b, &c);
fscanf(fp, " %d:%d", &b, &c);
fscanf(fp, "%d ->", &a);
fscanf(fp, "%d ->", &a);
fscanf(fp, " %d:%d", &b, &c);
fscanf(fp, " %d:%d", &b, &c);
fscanf(fp, "%d ->", &a);
fscanf(fp, " %d:%d", &b, &c);
fscanf(fp, " %d:%d", &b, &c);
fscanf(fp, " %d:%d", &b, &c);
An iteration of while (fscanf(fp, " %d:%d", &b, &c) == 2) { is consuming the "\n1" in "\n1 ->". This fouls the following fscanf(fp, "%d ->", &a), which starts at " ->" and stops the loop.
Code needs to detect the '\n'. format directives/specifiers like " " and "%d" consume end-of-line without reporting that.
Direct solution: As the file is lines of data, then read lines of text with fgets().
Use "%n" to record offset of scan.
// Generous maximum line size
#define LINE_N 1024
char line[LINE_N];
while (fgets(line, sizeof line, fp)) {
int a;
int n = 0;
// v--- space needed to consume trailing whitespace
sscanf(line, "%d -> %n", &a, &n) == 1) {
if (n == 0) {
fprintf(stderr, "Invalid line '%s'\n", line);
continue;
}
printf("%d ->", a);
char *p = line + n;
while (*p) {
int b,c;
n = 0;
// v--- space needed to consume trailing whitespace
sscanf(p, "%d:%d %n", &b, &c, &n);
if (n == 0) {
fprintf(stderr, "Invalid rest of line '%s'\n", p);
break;
}
printf(" %d:%d", b, c);
p += n;
}
printf("\n");
}
The algorithm isn't handling the newlines. So it gets stuck and the end of the first line and isn't able to read anything matching n ->.
One way that works reliably for all C RTL implementations is to use fgets() to read each whole line (including the newline at the end) and then use sscanf() to parse the string.
I think you just need to fseek one char ( newline ) at the last printf.
Related
I have this
void main(int argnum, char** input)
{
int a=0, b=0, c=0, d=0, e=0, f=0, g=0, h=0, i=0, j=0, k=0, l=0, m=0, n=0, o=0, p=0;
printf("Enter the numbers from 1 to 16, in any order(separate by comma) : ");
scanf_s("%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d", &a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p);
printf("%d " "%d " "%d " "%d \n", a, b, c, d);
printf("%d " "%d " "%d " "%d \n", e, f, g, h);
printf("%d " "%d " "%d " "%d \n", i, j, k, l);
printf("%d " "%d " "%d " "%d \n", m, n, o, p);
}
my display is
a 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
for some reason my variables other than a, arent being caught.. whats wrong?
(separate by comma)
If you're separating the numbers with commas, the second and subsequent scans will fails, because there's no way to turn a comma into an integer.
Scanning for an %d integer will:
skip white space (which does not include commas); then
scan as many characters as needed to populate an integer, up until the first character that's not part of an integer.
If the first non-whitespace character is a comma, that's not suitable for an integer. Easiest solution is probably just to tell user to separate with spaces rather than commas.
Let's begin with a cut-down version that exhibits the same behaviour (and with single strings rather than those disparate ones):
#include <stdio.h>
int main(void) {
int a=0, b=0;
printf("Enter numbers from 1 to 2 in any order (separate by comma): ");
scanf("%d %d", &a, &b);
printf("%d %d\n", a, b);
}
Entering 1,2 for that gives you 1 0 as per your code. Entering 1 2 (space-separated rather than comma) gives you 1 2, which is what you're after.
Of course, if you need the commas, you can put that into the format string as well:
scanf("%d ,%d", &a, &b);
This will:
%d - skip optional whitespace and read integer;
<space>: skip whitespace before comma;
,: skip comma;
%d - skip optional whitespace and read integer.
Of course, it goes without saying that you should always check things that can fail, if that failure can affect you adversely:
if (scanf("%d %d", &a, &b) != 2) { // expect two things scanned
fprintf(stderr, "Something went horribly wrong!\n");
exit(1);
}
#include<stdio.h>
void main(int argnum, char** input)
{
int a=0, b=0, c=0, d=0, e=0, f=0, g=0, h=0, i=0, j=0, k=0, l=0, m=0, n=0, o=0, p=0;
printf("Enter the numbers from 1 to 16, in any order(separate by comma) : ");
scanf("%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d" "%d", &a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p);
printf("%d " "%d " "%d " "%d \n", a, b, c, d);
printf("%d " "%d " "%d " "%d \n", e, f, g, h);
printf("%d " "%d " "%d " "%d \n", i, j, k, l);
printf("%d " "%d " "%d " "%d \n", m, n, o, p);
}
after taking each value from the keyboard please press enter button it will work with this code
In C, I need to input four variables using scanf
scanf("%c %d %d %d", &v1, &v2, &v3, &v4)
the first variable may take two values 'c' and 'q'
when I enter c then I enter the other variables it will do some calculations but when I want to quit I should enter 'q' only and not enter the rest of the variables but scanf does not move forward until I enter the rest of the variables
is there anyway to solve it, I am not sure if it is possible using scanf but if there is another function then I don't mind using it
"is there anyway to solve it"
Read a line of user input with fgets() ...
char buf[100];
if (fgets(buf, sizeof buf, stdin)) {
.. and then scan it
char v1;
int v2,v2,v3;
int cnt = sscanf(buf, "%c %d %d %d", &v1, &v2, &v3, &v4);
if (cnt >= 1 && v1 == 'q') Quit();
else if (cnt == 4 && v1 == 'c') Do_stuff(v2,v3,v4);
else puts("Bad input");
You should use multiple scanfs for this. For example
scanf("%c", &v1);
if(v1 == 'c'){
scanf("%d %d %d",&v2, &v3, &v4);
/*some staff*/
}
else{
/*another staff*/
}
I want to parse a const char *str string, and I need to read it by parts, with several calls to sscanf()
I have some example of what I could do if it was text of a file, which could be parsed with fscanf(), which updates the FILE *fp pointer to the position it stops reading:
fscanf(fp, "name %s ", name);
fscanf(fp, "date %*i ");
fscanf(fp, "{ ");
fscanf(fp, " isdst %*i ");
fscanf(fp, " yday %*i ");
fscanf(fp, " wday %*i ");
fscanf(fp, " year %i ", &year);
fscanf(fp, " mon %i ", &mon);
fscanf(fp, " mday %i ", &day);
But sscanf() doesn't update the pointer. Is there a way to do this?
EDIT:
From #pmg comment, I have this code now:
if (sscanf(str, " %lf%n", &a, &pos) != 1)
goto err;
str += pos;
if (sscanf(str, " %i%n", &b, &pos) != 1)
goto err;
str += pos;
which should be equivalent to a one line:
if (sscanf(str, " %lf %i", &a, &b) != 2)
goto err;
Is this what %n does?
Use "%n" conversion specifier in format string ... and corresponding variable.
I decided to refresh my C by wring a simple little program. I tried to read in from a file "myfile.txt", apply operations and print to stdout. The file contains one line:
2 + 3
the output I expect is:
5
but I found this to be much more complicated than I originally expected. At first I tried using getc() but kept getting segfaults, then I tried fscanf() there is no output from addition to stdin except the print statement that prints:
2 1556274040
Why is the output 2 1556274040? And is there a better way to try to apply operations read form a file, like some apply() function that I can use?
Here's my code:
int main()
{
int ans, num1, num2;
char oper;
FILE *pFile;
pFile = fopen("myfile.txt", "r");
if (pFile != NULL) {
fscanf(pFile, "%d", &num1);
fscanf(pFile, "%c", &oper);
fscanf(pFile, "%d", &num2);
printf ("%d %c %d", num1, oper, num2);
if (oper == '+') {
ans = num1 + num2;
printf(ans);
}
fclose(pFile);
}
return 0;
}
printf(ans);
Not a valid syntax to print an int variable.
Try this -
printf("%d\n",ans);
As you ask
you can use fgets instead of using fscanf to read contents of file but make sure you check their return.
Here's a possible solution...
#include <stdio.h>
int main() {
int ans, num1, num2;
char oper;
FILE *pFile;
pFile = fopen("myfile.txt", "r"); // might need to specify binary/text
if (pFile != NULL) {
// fscanf(pFile, "%d", &num1); need spaces in format specifier.
// fscanf(pFile, "%c", &oper);
// fscanf(pFile, "%d", &num2);
// one way to solve...
fscanf(pFile, "%d %c %d", &num1, &oper, &num2);
fclose(pFile); // stopping some errors
printf ("%d %c %d = ", num1, oper, num2);
} // end if
else
puts("fopen returned NULL");
if (oper == '+') {
ans = num1 + num2;
printf("%d",ans);
} // end if
return 0;
} // end main
I'm attempting input verification of the scanf function. I've already fixed the input to ignore blank space (" %c....").
Can anyone see what I've done wrong?
#include <stdio.h>
#include <stdlib.h>
int main() {
char c1, c2, c3;
int k, done = 0;
float x;
double y;
do {
printf("\n%s\n%s\n%s\n%s", "Input the following: three characters,", " an int,", " a float,", " and a double: \n");
if(scanf(" %c%c%c%d%f%lf", &c1, &c2, &c3, &k, &x, &y) == 6){
printf("\nHere is the data that you typed in: \n");
printf("%3c%3c%3c%5d%17e%17e\n\n", c1, c2, c3, k, x, y);
done = 1;
} else {
printf("Invalid input!");
}
} while (done != 0);
return EXIT_SUCCESS;
}
First of all variable done was not initialized and has an indeterminate value
int k, done;
//...
while(done != 1){
You must initialize it for example like
int k, done = 0;
But it would be better to write a more suitable loop. That is instead of the while loop it is better to use do-while loop. For example
int done = 0;
//...
do
{
printf("\n%s\n%s\n%s\n%s", "Input the following: three characters,", " an int,", " a float,", " and a double: \n");
if(scanf(" %c%c%c%d%f%lf", &c1, &c2, &c3, &k, &x, &y) == 6){
printf("\nHere is the data that you typed in: \n");
printf("%3c%3c%3c%5d%17e%17e\n\n", c1, c2, c3, k, x, y);
done = 1;
} else {
printf("Invalid input!");
}
} while ( done != 1 );
Secondly in the scanf call you should specify balnks for format specifiers %c
For example
if(scanf(" %c %c %c%d%f%lf", &c1, &c2, &c3, &k, &x, &y) == 6){
You forgot to initialize your variables. At least done should be initialized to something that's not 1.
You forgot to read and discard the rest of an invalid input line. Add e. g.
scanf("%*[^\n]%*c");
in the else block.