fscanf in C - how to determine comma? - c

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 , ".

Related

Problem with reading string from a file in C

I've tried to look for a similar problem but was unable to find it so I'm posting this. Here's the thing.
Let's say I have a file named text.txt. Now, the file consists of 3 integers and string, something like this:
4 59 32 This is sentence 1
5 9 130 Grass is green
3 12 149 I need help
I'm still learning C so I'm sorry if this is some easy type question etc. Here's the problem. I don't know how to read this. The same is if the string is at the beginning of the file like this
This is sentence 1 4 59 32
Grass is green 5 9 130
I need help 3 12 149
I know how to read it if I know the amount of words it will consist of (like if the file would be something like Name Surname Number Number Number) but this when I need to read entire, I have no idea.
Here's the code from comments. However, as #john pointed out, it's false right from the start since i gets first character and then I do scanf (still, I've tried out and with only numbers involved, fscanf gets correct values even though first character is read).
I was also thinking about some while loop with isalpha() and isspace() involved but to no avail.
while((i = fgetc(input)) != (int)(EOF))
{
fscanf(inputFile, "%d %d %d", &num1, &num2, &num3);
j=0;
while(i != (int)('\n'))
{
string[j++]=(char)i;
i = fgetc(inputFile);
}
string[j] = '\0';
printf("%d %d %d %s\n",br1, br2, br3, string);
it's false right from the start since i gets first character and then I do scanf
You're right, it's wrong. There's no need to consume a line's first character just to test for EOF - we can leave that to fscanf().
Also there's no need to read the string's characters one by one - fscanf() can read a string ending at \n with the conversion specification %[^\n].
If the input string length is not limited, we'd have to prevent the buffer overflow when the input string would need more memory than provided by string by adding a maximum field width. If you defined e. g. char string[100];, the maximum field width is 99, since the last char is needed for the terminating null character.
So we could write e. g.
while (fscanf(input, "%d %d %d %99[^\n]", &num1, &num2, &num3, string) == 4)
printf("%d %d %d %s\n", num1, num2, num3, string);

Dont read the first line of a text in C

I have a text file like this:
3 3 0
2 3 5
3 8 9
4 5 6
I want to put this numbers into a matrix.
The first line are the numbers of rows and columns to make the malloc for the matrix.
Then, the next lines are the numbers which are going to be on the matrix.
And I have this code:
int mat[3][3];
int i, j;
FILE *fp;
char c;
if((fp = fopen("texto.txt", "r")) == NULL){
printf("Error al abrir el archivo");
return -1;
}
for(i=0;i<3;i++){
for(j=0;j<3;j++){
mat[i][j]=0;
}
}
i = 0;
while (1)
{
if (feof(fp))
break;
fscanf (fp, "%[^\n]%d %d %d", &mat[i][0], &mat[i][1], &mat[i][2]);
i++;
}
fclose(fp);
for(i=0;i<3;i++){
for(j=0;j<3;j++){
printf("%d ", mat[i][j]);
}
printf("\n");
}
(Sorry for the spanish lines)
I dont have the malloc written becouse i just want to see if I create the matrix correctly knowing that is a 3x3.
So the problem is that I dont know how to make the matrix from the second line of the text file, and dont use the first line.
Thanks!
Read documentation of fscanf. Notice that spaces in the format control string may also skip newline characters, and that fscanf is returning the number of scanned items (which should matter to you). In some cases, you might be interested also by %n.
Be aware that your usage of fscanf is wrong (so is undefined behaviour) because %[^\n] expects an argument that you don't provide. With a good compiler like GCC, you should enable all warnings and debug info (e.g. compile with gcc -Wall -Wextra -g) and you'll get a warning.
If you want to skip the first line, start by reading every character (with fgetc) till you get EOF or '\n'. Or use fgets or getline(3) (on POSIX, like this) to read and ignore the first line.
If lines really matter, you could read every line (e.g. with fgets or getline(3)) and parse each line with e.g. sscanf or otherwise.

why does fscanf read garbage values

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.

Regarding about file input and output in C

I normally don't ask questions on here unless I'm really stuck! I was wondering if anyone can please explain why my code prints out a '5 47'. I understand why there is a 5, but not why there is a 47? I looked up the ASCII values for blankspace (32) and I tried changing the second letter to e, f, g, for example but the output remains '5 47' unchanged.
In general, when I use fscanf(fp, "%d", &variablename), does the fscanf skip over miscellaneous characters? For example: in my file test.txt I had "5 hello 6 ben jerry\n". How would I scan in the 5 and the 6? Would fscanf(fp, "%d %d", &test1, &test2) scan in the 5 and 6, skipping over the word "hello"?
Here is my simple code I am using to test output:
int main(int argc, char *argv[]) {
int blah, test;
FILE * fp;
fp = fopen(argv[1], "r");
fscanf(fp, "%d %d", &blah, &test);
printf("%d %d\n", blah, test);
return 0;
}
My file I am using as argv[1] contents:
5g
P.S. is FILE *fp an actual pointer to each character/number and does it work as a placeholder when it scans through the file? Is that why we need rewind(fp) once it hits the end of the file?
The operator %d looks for an integer, not a character. Because g is a character, not an integer, %d is getting confused and the output will not always be 5 47. The 47 could be anything. it could be 5 7, 5 23 etc. This is because the fscanf is not reading a second number, so no value is being assigned to test. Therefore, test remains at the value which was sitting in that piece of memory when the program was initiated.
To fix this, replace %d with %c and change the type of blah and test to int. Also, as WhozCraig said, it is good practise to check the return value of fscanf to check that two values have been found. This way, you can be sure that everything you're looking for has been found.
Note that the scanf() family of functions stop reading when they come across a character that is not expected by the format string. The unexpected character is left in the input for the next input operation to process.
If you want to read two integers that are definitely separated by a 'word' that is not an integer, then you will need to skip the word. If you don't know in advance what the word will be, you need to use assignment suppression (see the POSIX scanf() page for lots of information).
Hence, your code to read the two integers from input containing
5 hello 6 ben jerry
should be:
if (fscanf(fp, "%d %*s %d", &blah, &test) != 2)
…Oops; format error?…
Note that the code tests that it got the expected result. However, if you don't know whether there'll be a word between the two numbers, you are much better off using fgets() and sscanf() because you can try different parses of the same line:
char buffer[4096];
while (fgets(buffer, sizeof(buffer), fp) != 0)
{
if (sscanf(buffer, "%d %*s %d", &blah, &test) == 2)
…got two numbers with a word — let's go!
else if (sscanf(buffer, "%d %d", &blah, &test) == 2)
…got two numbers but no word — let's go!
else
…didn't recognize the format…
}
One of the major advantages of this is that you can report the error in terms of the complete line of input, rather than just the part that fscanf() didn't manage to work on.
Your last question, about a FILE *, is not a pointer to each character in the file. It is a handle which allows you to invoke functions that take a file pointer argument to read from or write to the associated file. However, you can't use indexing based on the file pointer (so fp[1024] does not identify the character at offset 1024 in the file or anything useful like that). If you want that sort of behaviour, you need a memory-mapped file (mmap() for POSIX systems).

How do i ignore characters after a certain spot on each line in C?

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

Resources