Skip remainder of line with fscanf in C - c

I'm reading in a file and after reading in a number, I want to skip to remaining part of that line. An example of a file is this
2 This part should be skipped
10 and also this should be skipped
other part of the file
At the moment I solve this by using this loop:
char c = '\0';
while(c!='\n') fscanf(f, "%c", &c);
I was however wondering whether there isn't a better way of doing this. I tried this, but for some reason it isn't working:
fscanf(f, "%*[^\n]%*c");
I would have expected this to read everything up to the new line and then also read the new line. I don't need the content, so I use the * operator. However, when I use this command nothing happens. The cursor isn't moved.

I suggest you to use fgets() and then sscanf() to read the number. scanf() function is prone to errors and you can quite easily get the format string wrong which may seem to work for most cases and fail unexpectedly for some cases when you find it doesn't handle some specific input formats.
A quick search for scanf() problems on SO would show how often people get it wrong and run into problems when using scanf().
Instead fgets() + sscanf() gives would give you better control and you know for sure you have read one line and you can process the line you read to read integer out it:
char line[1024];
while(fgets(line, sizeof line, fp) ) {
if( sscanf(line, "%d", &num) == 1 )
{
/* number found at the beginning */
}
else
{
/* Any message you want to show if number not found and
move on the next line */
}
}
You may want to change how you read num from line depending on the format of lines in the file. But in your case, it seems the integer is either located at first or not present at all. So the above will work fine.

#include <stdio.h>
int main(){
FILE *f = fopen("data.txt", "r");
int n, stat;
do{
if(1==(stat=fscanf(f, "%d", &n))){
printf("n=%d\n", n);
}
}while(EOF!=fscanf(f, "%*[^\n]"));
fclose(f);
return 0;
}

I wanted to parse the /proc/self/maps file, but only wanted the first 2 columns (start and end of address range). This worked fine with Linux gcc.
scanf("%llx-%llx %*[^\n]\n", &i, &e);
The trick was "%*[^\n]\n" which means skip a sequence of anything except the end of line, then skip the end of line.

Related

Trying to make a simple program (in C) that copies all non empty lines from a given text file into a new text file

This is what I tried doing (if the first charcacter of a line is '\n' it must necessarily be an empty line) but it gives me the error message: "Thread 1: EXC_BAD_ACCESS (code=1, address=0x68" at the line of fgets..
#include<stdio.h>
#define MAX_LEN 80
int main(int argc, char *argv[])
{
FILE *fin,*fout;
fin=fopen("poem_in.txt","r");
fout=fopen("poem_out.txt","w");
char line[MAX_LEN];
do {
fgets(line, MAX_LEN, fin);
if ((line[0])!='\n') fputs(line,fout);
} while(fgets(line, MAX_LEN, fin)!=NULL);
fclose(fin);
fclose(fout);
return 0;
}
I tried looking at the correction my professor gave but she used strcmp(line,"\n") so its not very useful and I don't get how its possible to compare a string and a char? Any help at all would be greatly appreciated and would be of great help in my studies!
You're calling fgets() twice each time through the loop. As a result, you only check every other line for being empty.
Do it like this instead.
while (fgets(line, MAX_LEN, fin)) {
if ((line[0])!='\n') fputs(line,fout);
}
If you're getting an error on the fgets() line, it's probably because the file wasn't opened successfully. You should check it first.
fin=fopen("poem_in.txt","r");
if (!fin) {
fprintf(stderr, "Can't open put file poem_in.txt\n");
exit(1);
}
fout=fopen("poem_out.txt","w");
if (!fout) {
fprintf(stderr, "Can't open output file poem_out.txt\n");
exit(1);
}
I tried looking at the correction my professor gave but she used strcmp(line,"\n") so its not very useful and i don't get how its possible to compare a string and a char?
Actually "\n" is not a char but a C string. Note that the char would be written as '\n' and here you have C string ("\n") and so it is possible to compare. Furthermore, you might want to take a look at the strcmp documentation http://www.cplusplus.com/reference/cstring/strcmp/
Remember, however, that strcmp would read strings from arguments for as long as the NULL character is not found meaning that a bad formatted input would make it read more than intended which could lead to crashes. In order to prevent there is a smarter equivalent of strcmp called strncpy which takes an additional parameter - the maximum length of the input. You have this defined with MAX_LEN ans so if you decide to follow the suggestion of your professor it is better to use strncmp http://www.cplusplus.com/reference/cstring/strncmp/
This is what I tried doing (if the first charcacter of a line is '\n' it must necessarily be an empty line) but it gives me the error message: "Thread 1: EXC_BAD_ACCESS (code=1, address=0x68" at the line of fgets..
Now, reading through your code there are a places that require your attention. For example you call fgets twice in the do-while loop:
do {
fgets(line, MAX_LEN, fin);
if ((line[0])!='\n') fputs(line,fout);
} while(fgets(line, MAX_LEN, fin)!=NULL);
You read a line from the file, and possibly write it to the another file. Then (inside the while) you read a line again but this time you do not look at it at all but instead do another read. Effectively you are skipping every 2nd line.
I think what you should do is start off with while loop instead of do-while and do the fgets in the while clausule. Then use strncmp to compare the output with a new-line character and save to the file the way you do it now. Something like:
while(fgets(...)) {
if strncmp {
fputs()
}
}

Read last line of a text file - C programming

I'm still a novice in C as I just started out. Here is a part of my function to open the file and then save the file lines into variables. I did while to loop until the end of file so I can get the last line, however it did not go as expected. So, I was wondering how can I get just the last line from a text file? Thank you.
tfptr = fopen("trans.txt", "r");
while (!feof(tfptr)){
fscanf(tfptr, "%u:%u:%.2f\n", &combo_trans, &ala_trans, &grand_total);
}
fclose(tfptr);
sample text file:
0:1:7.98
1:1:20.97
2:1:35.96
2:2:44.95
2:2:44.95
3:2:55.94
In your fscanf(tfptr, "%u:%u:%.2f\n", &combo_trans, &ala_trans, &grand_total);, the %.2f will cause problem.
You can't specify the precision for floating-point numbers in scanf() unlike in the case of printf(). See this answer.
So, instead of %.2f in the scanf format string, use just %f.
Since you just need the last line, you could just read the file line by line with fgets() and keep the last line.
while( fgets(str, sizeof(str), tfptr)!=NULL );
printf("\nLast line: %s", str);
fgets() will return NULL when the file is over (or if some error occurred while reading).
The lines in the input file are read one by one and when there are no more lines to read, str (a character array of suitable size) will have the line that was read last.
You could then parse the string in str with sscanf() like
sscanf(str, "%u:%u:%f", &combo_trans, &ala_trans, &grand_total);
Also, you should be checking the return value of fopen() to see if the file was really opened. fopen() will return NULL if some error occurred.
if( (tfptr = fopen("trans.txt", "r"))==NULL )
{
perrror("Error");
}
What did go wrong? Did you get another line?
Don't use "&" as you don't want to save a pointer. That can be the reason of failure.

How to get fscanf to stop if it hits a newline? [duplicate]

I'm trying to read a line using the following code:
while(fscanf(f, "%[^\n\r]s", cLine) != EOF )
{
/* do something with cLine */
}
But somehow I get only the first line every time. Is this a bad way to read a line? What should I fix to make it work as expected?
It's almost always a bad idea to use the fscanf() function as it can leave your file pointer in an unknown location on failure.
I prefer to use fgets() to get each line in and then sscanf() that. You can then continue to examine the line read in as you see fit. Something like:
#define LINESZ 1024
char buff[LINESZ];
FILE *fin = fopen ("infile.txt", "r");
if (fin != NULL) {
while (fgets (buff, LINESZ, fin)) {
/* Process buff here. */
}
fclose (fin);
}
fgets() appears to be what you're trying to do, reading in a string until you encounter a newline character.
If you want read a file line by line (Here, line separator == '\n') just make that:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
FILE *fp;
char *buffer;
int ret;
// Open a file ("test.txt")
if ((fp = fopen("test.txt", "r")) == NULL) {
fprintf(stdout, "Error: Can't open file !\n");
return -1;
}
// Alloc buffer size (Set your max line size)
buffer = malloc(sizeof(char) * 4096);
while(!feof(fp))
{
// Clean buffer
memset(buffer, 0, 4096);
// Read a line
ret = fscanf(fp, "%4095[^\n]\n", buffer);
if (ret != EOF) {
// Print line
fprintf(stdout, "%s\n", buffer);
}
}
// Free buffer
free(buffer);
// Close file
fclose(fp);
return 0;
}
Enjoy :)
If you try while( fscanf( f, "%27[^\n\r]", cLine ) == 1 ) you might have a little more luck. The three changes from your original:
length-limit what gets read in - I've used 27 here as an example, and unfortunately the scanf() family require the field width literally in the format string and can't use the * mechanism that the printf() can for passing the value in
get rid of the s in the format string - %[ is the format specifier for "all characters matching or not matching a set", and the set is terminated by a ] on its own
compare the return value against the number of conversions you expect to happen (and for ease of management, ensure that number is 1)
That said, you'll get the same result with less pain by using fgets() to read in as much of a line as will fit in your buffer.
Using fscanf to read/tokenise a file always results in fragile code or pain and suffering. Reading a line, and tokenising or scanning that line is safe, and effective. It needs more lines of code - which means it takes longer to THINK about what you want to do (and you need to handle a finite input buffer size) - but after that life just stinks less.
Don't fight fscanf. Just don't use it. Ever.
It looks to me like you're trying to use regex operators in your fscanf string. The string [^\n\r] doesn't mean anything to fscanf, which is why your code doesn't work as expected.
Furthermore, fscanf() doesn't return EOF if the item doesn't match. Rather, it returns an integer that indicates the number of matches--which in your case is probably zero. EOF is only returned at the end of the stream or in case of an error. So what's happening in your case is that the first call to fscanf() reads all the way to the end of the file looking for a matching string, then returns 0 to let you know that no match was found. The second call then returns EOF because the entire file has been read.
Finally, note that the %s scanf format operator only captures to the next whitespace character, so you don't need to exclude \n or \r in any case.
Consult the fscanf documentation for more information: http://www.cplusplus.com/reference/clibrary/cstdio/fscanf/
Your loop has several issues. You wrote:
while( fscanf( f, "%[^\n\r]s", cLine ) != EOF )
/* do something */;
Some things to consider:
fscanf() returns the number of items stored. It can return EOF if it reads past the end of file or if the file handle has an error. You need to distinguish a valid return of zero in which case there is no new content in the buffer cLine from a successfully read.
You do a have a problem when a failure to match occurs because it is difficult to predict where the file handle is now pointing in the stream. This makes recovery from a failed match harder to do than might be expected.
The pattern you wrote probably doesn't do what you intended. It is matching any number of characters that are not CR or LF, and then expecting to find a literal s.
You haven't protected your buffer from an overflow. Any number of characters may be read from the file and written to the buffer, regardless of the size allocated to that buffer. This is an unfortunately common error, that in many cases can be exploited by an attacker to run arbitrary code of the attackers choosing.
Unless you specifically requested that f be opened in binary mode, line ending translation will happen in the library and you will generally never see CR characters, and usually not in text files.
You probably want a loop more like the following:
while(fgets(cLine, N_CLINE, f)) {
/* do something */ ;
}
where N_CLINE is the number of bytes available in the buffer starting a cLine.
The fgets() function is a much preferred way to read a line from a file. Its second parameter is the size of the buffer, and it reads up to 1 less than that size bytes from the file into the buffer. It always terminates the buffer with a nul character so that it can be safely passed to other C string functions.
It stops on the first of end of file, newline, or buffer_size-1 bytes read.
It leaves the newline character in the buffer, and that fact allows you to distinguish a single line longer than your buffer from a line shorter than the buffer.
It returns NULL if no bytes were copied due to end of file or an error, and the pointer to the buffer otherwise. You might want to use feof() and/or ferror() to distinguish those cases.
i think the problem with this code is because when you read with %[^\n\r]s, in fact, you reading until reach '\n' or '\r', but you don't reading the '\n' or '\r' also.
So you need to get this character before you read with fscanf again at loop.
Do something like that:
do{
fscanf(f, "%[^\n\r]s", cLine) != EOF
/* Do something here */
}while(fgetc(file) != EOF)

Looking for a good way to read data from file in C

this is my first question in this site, and I've just started programming, please be patient with me.
I'm having some trouble with this code to read strings and intergers from a file, they are separated by a semicolon ";" and it starts with the number of lines. The file is something like this:
13;
A;15;B;1;0;0;0;
A;9;C;0;3;2;0;
A;9;D;0;4;0;2;
A;3;E;2;3;2;0;
A;7;F;5;5;3;1;
A;5;G;5;7;6;0;
A;13;H;0;0;0;0;
A;1;I;8;1;0;0;
A;1;J;2;2;1;0;
A;6;K;7;3;2;0;
A;5;L;2;4;3;0;
A;12;AA;0;3;2;0;
A;9;BA;0;1;0;0;
What I tried to do was to create a function that would receive a file pointer (fp) and the number of lines that was read in the main function. It would read the file and save the intergers and strings in matrices :
#include<stdio.h>
#include<stdlib.h>
char timesjogos[100][2][100];
int golsjogos[100][3];
int faltasjogos[100][3];
int camajogos[100][3];
int cverjogos[100][3];
int ReadGames(FILE *caminho,int njogos){
printf("starting to read jogos.\n");
int i=0;
while(fscanf(caminho, " %[^;];%d[^;];%[^;];%d[^;];%d[^;];%d[^;];%d[^;];",
timesjogos[i][0], &golsjogos[i][0], timesjogos[i][1], &golsjogos[i][1],
&faltasjogos[i][0], &camajogos[i][0], &cverjogos[i][0]) == 7)
{
if(i < njogos)
i++;
else
break;
}
}
int main()
{
FILE *fp;
int nbets;
fp = fopen("jogos.txt", "r");
if (!fp){
printf ("Error trying to open file.");
}
fscanf(fp, " %d[^;];", &nbets);
ReadGames(fp, nbets);
}
My doubts are about the %[^;]; I used to read each string up to the ; , should I use %d[^;] for the intergers? What is the correct way to do it?
Also, I'm using global variables to save the information read, the problem is that they can be not large enough to save huge amounts of lines (my professor made a 24180 lines file to test our codes). I was thinking about using the number of lines it gives in the first line to make pre-sized matrices inside the function, but how can I return or save it after the function ends?
I'm sorry for the huge code, but I wanted to show all the details. I would be very thankful for your more experienced help :D
The %[^;] notation reads a string consisting of any number of non-semicolons. The parsing stops when a semicolon is encountered. With numbers, the parsing stops at a semicolon anyway; the semicolon is not a part of the representation of a number.
Your use of %d[^;] means that fscanf() is looking for an integer (%d), then an open square bracket, caret, semicolon and close square bracket. These don't appear in the input, of course, so the scanning fails.
Therefore, your input loop should probably be:
while (fscanf(caminho, " %[^;];%d;%[^;];%d;%d;%d;%d;",
timesjogos[i][0], &golsjogos[i][0], timesjogos[i][1],
&golsjogos[i][1], &faltasjogos[i][0], &camajogos[i][0],
&cverjogos[i][0]) == 7)
{
...
}
You might prefer to specify a maximum length for the %[^;] conversion specifications; %99[^;] would be appropriate since the third dimension of timesjogos is 100. There's an off-by-one difference between the length specified and the length used (enshrined because of ancient history; it was that way before the first C standard, and the C standard codified existing practice).

Use of fgets() and gets()

#include <stdlib.h>
#include <stdio.h>
int main() {
char ch, file_name[25];
FILE *fp;
printf("Enter the name of file you wish to see\n");
gets(file_name);
fp = fopen(file_name,"r"); // is for read mode
if (fp == NULL) {
printf(stderr, "There was an Error while opening the file.\n");
return (-1);
}
printf("The contents of %s file are :\n", file_name);
while ((ch = fgetc(fp)) != EOF)
printf("%c",ch);
fclose(fp);
return 0;
}
This code seems to work but I keep getting a warning stating "warning: this program uses gets(), which is unsafe."
So I tried to use fgets() but I get an error which states "too few arguments to function call expected 3".
Is there a way around this?
First : Never use gets() .. it can cause buffer overflows
second: show us how you used fgets() .. the correct way should look something like this:
fgets(file_name,sizeof(file_name),fp); // if fp has been opened
fgets(file_name,sizeof(file_name),stdin); // if you want to input the file name on the terminal
// argument 1 -> name of the array which will store the value
// argument 2 -> size of the input you want to take ( size of the input array to protect against buffer overflow )
// argument 3 -> input source
FYI:
fgets converts the whole input into a string by putting a \0 character at the end ..
If there was enough space then fgets will also get the \n from your input (stdin) .. to get rid of the \n and still make the whole input as a string , do this:
fgets(file_name,sizeof(file_name),stdin);
file_name[strlen(file_name)] = '\0';
Yes: fgets expects 3 arguments: the buffer (same as with gets), the size of the buffer and the stream to read from. In your case your buffer-size can be obtained with sizeof file_name and the stream you want to read from is stdin. All in all, this is how you'll call it:
fgets(file_name, sizeof file_name, stdin);
The reason gets is unsafe is because it doesn't (cannot) know the size of the buffer that it will read into. Therefore it is prone to buffer-overflows because it will just keep on writing to the buffer even though it's full.
fgets doesn't have this problem because it makes you provide the size of the buffer.
ADDIT: your call to printf inside the if( fp == NULL ) is invalid. printf expects as its first argument the format, not the output stream. I think you want to call fprintf instead.
Finally, in order to correctly detect EOF in your while-condition you must declare ch as an int. EOF may not necessarily fit into a char, but it will fit in an int (and getc also returns an int). You can still print it with %c.
Rather than ask how to use fgets() you should either use google, or look at the Unix/Linux man page or the VisualStudio documentation for the function. There are hundreds of functions in C, C++ and lots of class objects. You need to first figure out how to answer the basics yourself, so that your real questions stand a chance of being answered.
If you are new to C, you are definitely doing the right thing of experimenting, but take a look at other code, as you go along, to learn some of the tips/tricks of how code is written.

Resources