Read last line of a text file - C programming - c

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.

Related

How can I get one line and other lines in two parts in C?

I try to get input from a text file. First line of the text only contains a number, then others related with it like that;
4
ssss
sss
ss
s
I used fgets function for getting these lines from file, but I want to use "4" and the other lines in different functions.
I was getting both these lines with fgets like that;
char inp[150];
int i;
FILE *fp;
while(1) {
if(fgets(inp, 150, fp) == NULL) break;
printf("%s",inp);
i++;
}
I used printf for only see that this code getting all lines or not. It is getting all lines same with input, but when I try to print first line of the input "inp[0]", I expect to print "4", but it prints "s" again.
Therefore, I can't use or get the number which is in the first line. How can I print or use first line independently from others.
By the way, the number and the other lines ,which are related with it, can change with another inputs.
Pass the file pointer to the functions, and have them attempt to read the lines.
That's a basic parser for you.
Don't forget to:
Do error handling, and properly indicate if a read failed.
Reset the file pointer position in case of failure.
Store the result of fgetpos at the beginning and restore it with fsetpos
The problem with your code is that fgets(inp, 150, fp) reads until newline, 149 characters read or EOF.
So each timefgets(inp, 150, fp) you store new values in inp. And last value is s.
Try to use fgetc and store character by character in inp.

How do I check if the line is over?

I ran into a problem today. I can't find a way to check if a line in a file is over and the words are read from the next one already. I read word by word from the file using fscanf, then process the word as I need to and print it out into another file but there is a problem.
for example my data file is:
Hello, how are you
doing?
and the result file shows:
Hello, how are you doing?
but i need the words to be in the same lines from which I took them. Please keep in mind that I need those words one by one, that is why I don't use getline()
here is my code of how I read words from the file:
while( fscanf(file, "%s", A) != EOF )
{
check(A, B, &a); // I edit the words and put them in B string
// which is printed to the write file
}
Thank you for any tips!
Read the line into a string with getline() or fgets(), then use sscanf to get the words out of this string.
You can use a simple logic instead, like matching strings like . or ? which generally ends lines.
You need to check for end of line by adding check.
As the end-of-line is represented by the newline character, which is '\n'. so in while loop instead of copying entire thing do it line by line with the help of check for '\n'

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.

Skip remainder of line with fscanf in 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.

Write and Display a stream with format on C

I'm in my first year of Computer Sciences and I have to design a procedure that writes to a file with format (fprintf) and displays it with format (fscanf). But I can't get it to run properly; it compiles but when it gets to the fscanf part, it crashes. I've been looking around reference sites, YouTube videos and stuff but I can't get it to work without any success.
Except for the last 2 lines of codes, it does everything great. Its capable of writing the records I enter, in the .txt file. The problem is with the use of fscanf itself.
void write_with_format()
{
char name_of_file[100] = "grades.txt";
FILE *arch;
arch = fopen (name_of_file, "a");
char name[50];
char career[50];
char grades[100];
char total;
printf("Give me the name");
gets(name);
printf("Give me the career");
gets(career);
printf("Give me the grade");
gets(grades);
getchar();
fprintf (arch, "%s,%s,%s\n",name,career,grades);
fscanf(arch,"%s %s %f",&name,&career,&grades);
printf("%s %s %f",name,career,grades);
}
I'd appreciate any help regarding my code or the proper use of fscanf, thank you all.
This line is all wrong:
fscanf(arch,"%s %s %f",&name,&career,&grades);
grades is declared as char grades[100];, ie. a string, however you're trying to read a float into it. Same goes for the printf line below it, you're using %f and telling printf that you're passing a float, however you're passing an array. You also don't need to use the address-of operator (&) when passing arrays to functions, as you have with fscanf.
You should use fclose to flush the buffer and close the file stream once you're done with reading/writing a file.
Back to the fscanf line, what exactly do you expect it to do? The file position inidcator is at the end of the file, just after where you've appended the line produced by fprintf. Check the return value of fscanf and you'll see that it's returning EOF to report an error. The specific error value is stored in errno.
You can use rewind or fseek to set the position to the start of the file or back a certain amount, or you could always reopen the file. I know that I at least wouldn't have my read code in a write_with_format function.
gets is unsafe and should not be used as it has the potential to cause buffer overflows, use fgets(stdin, SIZE...) instead.
Turn up your compiler warnings. If by chance you're using gcc, the flag is -Wall. Just because your code compiles, doesn't mean that it's going to work properly (or at all).
You declare grades as an array of char's but are trying to read into it a float.

Resources