fscanf not scanning file - c

I am trying to scan a file using fscanf and put the string into an char array of size 20 as follows:
char buf[20];
fscanf(fp, "%s", buf);
The file fp currently contains: 1 + 23.
I am setting a pointer to the first element in buf as follows:
char *p;
p = buf;
Printing buf, printf("%s", buf) yields only 1. Trying to increment p and printing prints out rubbish as well (p++; printf("%c", *p)).
What am I doing wrong with fscanf here? Why isn't it reading the whole string from the file?

fscanf (and related functions) with the format-string "%s" will try to read as many characters as it can without including a whitespace, in this case it will find the first character (1) and store it, then it will hit a space () and therefore stop searching.
If you'd like to read the whole line at once consider using fgets, it is also safer to use since you need to specify the size of your destination buffer as one of it's arguments.
fgets will try to read at maximum length-of-buffer minus 1 characters (last byte is saved for the trailing null-byte), it will stop at either reading that many characters, hitting a new-line or the end of the file.
fgets (buf, 20, fp);
Links to documentation
codecogs.com - scanf, fscanf and related functions - <stdio.h>
codecogs.com - fgets - <stdio.h>

Related

What happens with extra memory using fscanf?

I'm new to C and I have a couple questions about fscanf. I wrote a simple program that reads the contents of a file and spits it back out on the command line:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char* argv[1])
{
if (argc != 2)
{
printf("Usage: fscanf txt\n");
return 1;
}
char* txt = argv[1];
FILE* fp = fopen(txt, "r");
if (fp == NULL)
{
printf("Could not open %s.\n", txt);
return 2;
}
char s[50];
while (fscanf(fp, "%49s", s) == 1)
printf("%s\n", s);
return 0;
}
Let's say the contents of my text file is just "C is cool.", which will output:
C
is
cool.
So I have two questions here:
1) Does fscanf assume that the placeholder "%s" will be a single word (an array of chars only)? According to this program's output, spaces and line breaks seem to prompt the function to return. But what if I wanted to read a whole paragraph? Would I use fread() instead?
2) More importantly I'm wondering what happens with all of the unused space in the array. On the first iteration, I think s[0] = "C" and s[1] = "\0", so are s[2] - s[49] just wasted?
EDIT: while (fscanf(fp, "%**49**s", s) == 1) - thanks to #M Oehm for pointing this out - enforcing strong limit here to prevent dangerous buffer overflows
1) Does fscanf assume that the placeholder "%s" will be a single word
(an array of chars only)? According to this program's output, spaces
and line breaks seem to prompt the function to return. But what if I
wanted to read a whole paragraph? Would I use fread() instead?
The %s specifier reads single words that are delimited by white space. The scanf family of functions are very cerude; they do not normally distinguish between line breaks and spaces, for example.
A line is anything up to the next newline. There is no concept of paragraph, but you might consider anything between blank lines a paragraph. The function to read lines of text is fgets, so you could read lines until you find an empty one. (fgets retains the newline at the end, mind.)
fread is a function for reading binary data. It is not useful for reading structured texts. (But it can be used to read the contents of a whole text file at once.)
2) More importantly I'm wondering what happens with all of the unused
space in the array. On the first iteration, I think c[0] = 'C' and
c[1] = '\0', so are c[2] - c[49] just wasted?
You are right, the data after the null ternimator isn't used. "Wasted" is too negative – with user input you don't know whether you encounter a longer word eventually. Because dynamic allocation requires some care in C, allocating "enogh for most cases" is a goopd practice in C. You should enforce the hard limit when reading, though, to prevent buffer overruns:
fscanf(fp, "%49s", s)
The issue of "wasted" memory becomes more serious if you have an array of arrays of 50 chars. Most of the words will be much shorter than 50 chars. Here, the extra memory might eventually hurt you. 48 extra characters for reading a line are okay, though.
(A strategy to save "compact" arrays of chars is to have a running array of chars that is a concatenation of all strings, including their terminators. The word array is then an array of piointers into that master string.)
You use specifier %s which will read and store data in array s until it encounters a space or newline . As soon as it encounters space fscanf returns.
I think c[0] = "C" and c[1] = "\0", so are c[2] - c[49] just wasted?
Yes , s[0]='C' and s[1]='\0' and you probably can't do anything about the size of array being much more.
If you want complete string "C is cool" stored in array use fgets.
#define len 1000
char s[len];
while(fgets(s,len,fp)!=NULL) {
//your code
}

C - fgets() - length of newline char

I am trying to read 1 line and I am not sure how newline char is represented. Should I consider it as 2 chars or 1 char, when reading it from file by fgets() ? For example, I have a line of 15 chars + new line in file. So how should I safely allocate string and read that line?
At first, I tried this:
char buf[16];
fgets(buf, 16, f);
It read the line correctly without newline char and I assume that buf[15] holds the null character.
However, when I want to read and store the newline char, it doesn't work as I thought. As far as I know, '\n' should be considered as one char and take just one byte, so to read it, I just need to read one more char.
But when i try this
char buf[17];
fgets(buf, 17, f);
it does completely the same thing than previous example - there is now newline char stored in my string (I am not sure where null char is stored in this case)
To read entire line with newline I need to do this
char buf[18];
fgets(buf, 18, f);
OR this (it works, but I am not sure if it's safe)
char buf[17];
fgets(buf, 18, f);
So the questions is, why do I need to allocate and read 18 chars, when the line has only 15 chars + newline?
You need to provide buffer space for the 15-chars of text, up to 2 characters for the new line (to handle Windows line termination of \r\n), and one more for the null termination. So that's 18.
Like you did here:
char buf[18]; fgets(buf, 18, f);
The num parameter to fgets tells the call the size of your buffer it's writing to.
I am trying to read 1 line and I am not sure how newline char is represented.
In text mode, newline is '\n' and that's true on any conform C implementation and I wouldn't use fgets on anything but a text mode stream (I don't know -- and I don't want to know -- how it works in binary mode on an implementation using \r as end of line marker, or worse using an out of band end of line marker, I wouldn't be surprised it looks for a \n and never find one thus try to read until the end of file).
You should allocate space for the maximal line length, included the newline plus the terminating NUL and more important you must never lie the fgets about the length of the buffer. You can check if the buffer was long enough as the newline won't be present if it isn't.
The matter is about the espace sequence that lets you test for a newline, it is two characters \0x0d\0x0a but when using a strcmp and need to provide a string for this and a length, the C escape code holds in one character, so you must:
if(strncmp(&buff[i], "\n", 1) == 0)
which would not work with a length of two. Don't ask me why.

I need fscanf advice

I want to fprintf() 3 strings to a file, all on the same line.
The first two cannot contain spaces while the 3rd may. I.E. word word rest of line
Can some one tell me how to fscanf() that into 3 variables?
I don't mind putting some delimiters if it makes it easier. E.G. [word] [word] [rest of line]
You can do it without delimiters, too:
char s1[32], s2[32], s3[256];
if(sscanf(line, "%31s %31s %255[^\n]", S1, S2, S3) == 3)
/* ... */
This should work, as long as the input line actually does end with a newline.
Of course, you should adjust the string sizes to fit. Also you can get trickery with the preprocessor to avoid repeating the sizes, but doing so makes it more complicated so I avoided that for this example.
You could use scanf to scan two words, then use fgets to get the rest of the line.
FILE *f = stdin; // or use fopen to open a saved file
// use buffers large enough for your needs
char word1[20];
char word2[20];
char restOfLine[100];
// make sure fscanf returns 2 (indicating 2 items scanned successfully)
fscanf(f, "%20s %20s", word1, word2);
// make sure fgets returns &restOfLine[0]
fgets(restOfLine, sizeof restOfLine, f);
Note that if fgets encounters a '\n' character, it is put into the buffer as well, so if you don't want it, you'll have to strip it out manually. If fscanf returns something other than 2, or fgets returns NULL, then there was a problem reading your input.

How to use scanf \ fscanf to read a line and parse into variables?

I'm trying to read a text file built with the following format in every line:
char*,char*,int
i.e.:
aaaaa,dfdsd,23
bbbasdaa,ddd,100
i want to use fscanf to read a line from file, and automatically parse the line into the varilables string1,string2,intA
What's the correct way of doing it ?
Thanks
Assuming you have:
char string1[20];
char string1[20];
int intA;
you could do:
fscanf(file, "%19[^,],%19[^,],%d\n", string1, string2, &intA);
%[^,] reads a string of non-comma characters and stops at the first comma. 19 is the maximum number of characters to read (assuming a buffer size of 20) so that you don't have buffer overflows.
If you really cannot make any safe assumption about the length of a line, you should use getline(). This function takes three arguments: a pointer to a string (char**), a pointer to an int holding the size of that string and a file pointer and returns the length of the line read. getline() dynamically allocates space for the string (using malloc / realloc) and thus you do not need to know the length of the line and there are no buffer overruns. Of course, it is not as handy as fscanf, because you have to split the line manually.
Example:
char **line=NULL;
int n=0,len;
FILE *f=fopen("...","r");
if((len=getline(&line,&n,f)>0)
{
...
}
free(line);
fclose(f);

How to skip a line when fscanning a text file?

I want to scan a file and skip a line of text before reading. I tried:
fscanf(pointer,"\n",&(*struct).test[i][j]);
But this syntax simply starts from the first line.
I was able to skip lines with scanf with the following instruction:
fscanf(config_file, "%*[^\n]\n");
The format string matches a line containing any character including spaces. The * in the format string means we are not interested in saving the line, but just in incrementing the file position.
Format string explanation:
% is the character which each scanf format string starts with;
* indicates to not put the found pattern anywhere (typically you save pattern found into parameters after the format string, in this case the parameter is NULL);
[^\n] means any character except newline;
\n means newline;
so the [^\n]\n means a full text line ending with newline.
Reference here.
fgets will get one line, and set the file pointer starting at the next line. Then, you can start reading what you wish after that first line.
char buffer[100];
fgets(buffer, 100, pointer);
It works as long as your first line is less than 100 characters long. Otherwise, you must check and loop.
It's not clear what are you trying to store your data into so it's not easy to guess an answer, by the way you could just skip bytes until you go over a \n:
FILE *in = fopen("file.txt", "r");
Then you can either skip a whole line with fgets but it is unsafe (because you will need to estimate the length of the line a priori), otherwise use fgetc:
char c;
do {
c = fgetc(in);
} while (c != '\n');
Finally you should have format specifiers inside your fscanf to actually parse data, like
fscanf(in, "%f", floatVariable);
you can refer here for specifiers.
fgets would work here.
#define MAX_LINE_LENGTH 80
char buf[MAX_LINE_LENGTH];
/* skip the first line (pFile is the pointer to your file handle): */
fgets(buf, MAX_LINE_LENGTH, pFile);
/* now you can read the rest of your formatted lines */

Resources