I have a simple file as below:
1
3
a 7
and when I run the code below, I get some unexpected result. I initially try to read the first two integers and then read the character a and number 7. There is no white space after the number 1 or 3.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main(int argc, char **argv)
{
FILE *f;
f = fopen(argv[1],"r");
int num1, num2, num3;
char t;
fscanf(f, "%d",&num1);
fscanf(f, "%d",&num2);
fscanf(f, "%c %d", &t, &num3);
printf("%c %d\n", t, num3);
}
EDIT:
Input is the file with the content:
1
3
a 7
and the output is a new line and some garbage. Expected output should be a 7
EDIT 2: it reads correctly 1 and 3. Then trying to read a single character a if fails
Loooks at what happens when you run this:
fscanf(f, "%d",&num1);
skips whitespace (of which there is none), then reads an integer (1)
fscanf(f, "%d",&num2);
skips whitespace (the newline at the end of the first line) then reads an integer (3)
fscanf(f, "%c %d", &t, &num3);
reads the next caharcter from the input (a newline), then skips whitespace (none) and tries to read an integer. The next input character is 'a', so this fails, and the fscanf call returns 1 without writing anything into num3.
So the problem you are having is that due to the fact that %c does NOT skip whitespace, you are reading the whitespace (newline) instead of the character you expect. The most obvious solution is to add a space () to the format to skip whitespace:
fscanf(f, " %c%d", &t, &num3);
Note that I've also removed the space before %d, as it is redundant (%d always skips whitespace).
In addition, it is always a good idea to check the return value of fscanf to make sure it is reading the number of input items you expect.
Related
I wrote the following code:
#include <stdio.h>
int main()
{
int a, b;
printf("Enter values of a and b\n");
scanf(" %d%d ", &a, &b); // Note the two spaces before and after %d
// ^This^
printf("a = %d b = %d\n", a, b);
return 0;
}
The program run something like this:
aps120797#XENON-PC:/mnt/d/Codes/LetUsC$ ./a.out
Enter values of a and b
1
2
3
a = 1 b = 2
My question is that why is it taking three inputs instead of two (two %d is in scanf() ) and even if it is taking three, why is it skipping the last one?
Space in a format string means to skip over any sequence of whitespace (spaces, newlines, tabs) in the input, and stops scanning when it gets to the first non-white character or the end of the input. That next character is left in the input buffer, so it can be read by the next format operator (if there is one) or the next input operation (if you were to call getc() after your scanf(), it would read the '3' character.
When you put a space at the end of the format string, it skips over the newline after 2, and keeps scanning until it gets to the next non-white character. So it has to get to the 3 before it stops.
When I compile my program I get no error, but when I start it I get a "Segmentation fault". The FILE I try to read is build like this:
322;Peter;m
233;Chad;m
211;Lisa;w
I have the strong feeling my sscanf function is the issue.
Please help me.
#define MAXCHAR 30
#define MAXZEILE 40
void speicher(char Z[MAXCHAR]){
FILE *QUELL;
int a;
char n[MAXCHAR];
char g;
char string[MAXZEILE];
QUELL=fopen(Z,"r");
fgets(string, MAXZEILE, QUELL);
sscanf(string, "%d;%s;%c", &a, n, &g);
printf("%d, %s, %c", a, n, g);
fclose(QUELL);
}
My bad:
the MAXCHAR for the FILE input was to low.
The FILE had more than 30 chars.
In your sscanf %s does not know when to stop:
sscanf(string, "%d;%s;%c", &a, n, &g);
Without properly tokenizing on ;, %s will keep grabbing input until the next whitespace (which in your case will be the end of the line). It should be changed to
sscanf(string, "%d;%[^;];%c", &a, n, &g);
The %[^;] specifies to grab characters that are not a ; thus achieving the desired result.
For more robustness, you may want to look into using strtok to first separate it ; and then process each individual segment.
I assume that to your purposes the lines written below are enough
ReturnVal = sscanf(strinp1, "%d %c %100[^;] %c %c", &a, &Separator1,
n,&Separator2, &g);
Read an integer
Read then the character ';'
Read at most 100 characters, stop reading encountering the character ';'
Read then again the character ;
Read the next character. (man or woman???).
Here is my code to repeatedly read three variables separated by whitespace from user. The format of input should be 'char int int'(e.g b 3 3 ). I use the return value of scanf function to ensure input is exactly three variables.
#include <stdio.h>
int main(void){
int x, y, nargs;
char command;
while(1){
nargs = scanf("%c %d %d", &command, &x, &y);
printf("%d\n",nargs);
if(nargs != 3){
printf("error\n");
break;
}
}
return 0;
}
Input and Output:
g 4 4
3
b 3 3
1
error
The first line input is no problem. But when I input second line, it shows scanf() only read one variable from this line. What's the problem of my code?
The problem is the \n newline hidden between the two input lines you are sending to stdin. After first scanf you have a '\n' pending on the input stream, then you append "b 3 3" so the whole buffer looks like "\nb 3 3".
Then scanf is called again and \n is matched to %c, after scanf expects whitespace but the buffer has 'b' so it fails after assigning \n to command.
You could try matching with
nargs = scanf("%c %d %d ", &command, &x, &y);
^
so that newline is eaten with the previous scanf, from cppreference:
any single whitespace character in the format string consumes all available consecutive whitespace characters from the input
nargs = scanf("%1s %d %d", &command, &x, &y);
The problem is with the %c for one character. If you change it for %1s you expect an string of one character (the same) but without problems.
With the %c it is better to send the result to an array, and access the content with its index.
I am trying to input txt files into my C program that look something like this
123 x 182 //this is a comment in the file
1234 c 1923 //this is another comment in the file
12 p 3 //this is another comment in the file
I need to store the int, the single character and the other int on each line and then I want to ignore everything else on the line. Here is what I tried....
while (fscanf(file, "%d %c %d", &one,&two,&three) !=EOF)
{
printf("%d %c %d\n", one,two,three);
}
Right now I'm just printing out the values to test the process. So, if I test this with a file that does not have any comments or extra stuff after the first 3 things I need, it works perfectly. But if there is extra stuff, I get stuck in an infinite loop where the first line is repeatedly printed.
There may be a better way in C, but you could add a loop inside of your current loop to read in the remaining characters until you hit a newline.
while (fscanf(file, "%d %c %d", &one,&two,&three) !=EOF)
{
printf("%d %c %d\n", one,two,three);
while(fgetc(file) != '\n'){};
}
This should break out of the nested while loop as soon as the character it gets is a newline, and the next fscanf will begin on the next line.
If you're libc supports POSIX 2008 (like at least glibc on linux does), you can use getline and sscanf:
int len;
char *line;
while (getline(&line, &len, file) != -1) {
sscanf(line, "%d %c %d", &one, &two, &three);
printf("%d %c %d\n", one,two,three);
...
}
I am reading set of numbers from file by fscanf(), for each number I want to put it into array. Problem is that thoose numbers are separated by "," how to determine that fscanf should read several ciphers and when it find "," in file, it would save it as a whole number? Thanks
This could be a start:
#include <stdio.h>
int main() {
int i = 0;
FILE *fin = fopen("test.txt", "r");
while (fscanf(fin, "%i,", &i) > 0)
printf("%i\n", i);
fclose(fin);
return 0;
}
With this input file:
1,2,3,4,5,6,
7,8,9,10,11,12,13,
...the output is this:
1
2
3
4
5
6
7
8
9
10
11
12
13
What exactly do you want to do?
I'd probably use something like:
while (fscanf(file, "%d%*[, \t\n]", &numbers[i++]))
;
The %d converts a number, and the "%*[, \t\n]" reads (but does not assign) any consecutive run of separators -- which I've defined as commas, spaces, tabs, newlines, though that's fairly trivial to change to whatever you see fit.
fscanf(file, "%d,%d,%d,%d", &n1, &n2, &n3, &n4); but won't work if there are spaces between numbers. This answer shows how to do it (since there aren't library functions for this)
Jerry Coffin's answer is nice, though there are a couple of caveats to watch for:
fscanf returns a (negative) value at the end of the file, so the loop won't terminate properly.
i is incremented even when nothing was read, so it will end up pointing one past the end of the data.
Also, fscanf skips all whitespace (including \t and \n if you leave a space between format parameters.
I'd go for something like this.
int numbers[5000];
int i=0;
while (fscanf(file, "%d %*[,] ", &numbers[i])>0 && i<sizeof(numbers))
{
i++;
}
printf("%d numbers were read.\n", i);
Or if you want to enforce there being a comma between the numbers you can replace the format string with "%d , ".