txt file:
44.56 john doe
100.21 jane doe
How to calculate sum of numbers? This function give 0
double get_sum(FILE *out)
{
double sum = 0;
double value;
char name;
char surname;
while(fscanf(out, "%lf %s %s", &value, name, surname) != EOF)
{
sum += value;
}
return sum;
}
Just tell fscanf
to ignore the name
and surname
slots like this:
double get_sum(FILE *out) {
double sum = 0;
double value;
while (fscanf(out, "%lf%*s%*s", &value) != EOF) {
sum += value;
}
return sum;
}
The trouble is that you where passing pointers to char
instead of a pointer to a char array that can hold the content. Since you didn't it overflowed and caused undefined behavior.
But if you really wanted to also read in the names then try:
double get_sum(FILE *out) {
double sum = 0;
double value;
char name[5];
char surname[4];
while (fscanf(out, "%lf%s%s", &value, name, surname) != EOF) {
sum += value;
}
return sum;
}
Here the buffers are just long enough to accommodate the example text files data. In real life (if you needed it) you would have the big enough to handle the longest name. The important difference to your original code is that name
and surname
are pointers that the fscanf
function expects.
But given that names sometimes are unpredictable in length, after reading the value on the line, just read the remaining line into a buffer and just ignore it.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
double get_sum(FILE *in) {
double sum = 0;
double value;
char *remainingLine = NULL;
size_t bufLen = 0;
while (fscanf(in, "%lf", &value) == 1) {
sum += value;
// ignore remaining character in line
getline(&remainingLine, &bufLen, in);
}
free(remainingLine);
return sum;
}
int main(void) {
FILE *f = fopen("text.txt", "r");
assert(f);
double s = get_sum(f);
fclose(f);
printf("Sum is %f", s);
}
with text.txt
file containing
1.03 First Surname
2.2Here is another long "name" (sum should be 10.63)
3.4 first middle last (next line is lonely and last)
4
Running the this last program should produce simething along the lines of
Sum is 10.630000
In the line
while(fscanf(out, "%lf %s %s", &value, name, surname) != EOF)
it is not good to compare the return value of the function fscanf
with EOF
. For example, if the function is only able to match one argument, then it will return 1
, but your program will still behave as if all 3
arguments had been matched, and your program will attempt to process non-existant data. Therefore, you should write the following instead:
while( fscanf(out, "%lf %s %s", &value, name, surname) == 3 )
However, that is probably not the reason for the immediate problem that you are having. That problem is probably due to the fact that the %s
conversion format specifier requires a pointer to write to. However, you are instead passing the value of (not a pointer to) a single char
.
Your compiler should have warned you about this, assuming that you have warnings enabled. See this question for further information: Why should I always enable compiler warnings?
In order to solve this problem, you should change the lines
char name;
char surname;
to:
char name[50];
char surname[50];
Also, you should probably limit the number of characters written to these strings, in order to prevent a buffer overflow , like this:
while( fscanf(out, "%lf %49s %49s", &value, name, surname) == 3 )
For line-based input, I generally recommend that you read one line at a time with the function fgets
. You can then use the function sscanf
on every line, in order to parse it.
If you use instead fscanf
as you do now, and if it does not match exactly 3 fields in one line, then the parser will go out of sync with the lines, and it won't be able to resync itself at the start of a new line, which will probably mean that your program will misbehave for the rest of the file, instead of only misbehaving for a single line.
Here is a program which uses fgets
and sscanf
instead:
#include <stdio.h>
double get_sum( FILE *fp )
{
char line[200];
double sum = 0;
while ( fgets( line, sizeof line, fp ) != NULL )
{
double value;
char name[50];
char surname[50];
if ( sscanf( line, "%lf %49s %49s", &value, name, surname ) == 3 )
{
sum += value;
}
else
{
printf( "WARNING: skipping line due to parse failure!\n" );
}
}
return sum;
}
int main( void )
{
//calling this function would also work for an opened file, but
//for simplicity, I am only passing it "stdin"
double sum = get_sum( stdin );
printf( "The sum is: %lf\n", sum );
}
With the input
44.56 john doe
100.21 jane doe
from the question, this program has the following output:
The sum is: 144.770000
If you now instead supply the program with input that contains one line of invalid input
44.56 john doe
invalid_input_line
100.21 jane doe
it will only fail with parsing that invalid line, but will still process the other lines properly:
WARNING: skipping line due to parse failure!
The sum is: 144.770000
As already explained, your program is able to recover from this error because it is reading one line at a time using fgets
, and it is using sscanf
instead of fscanf
. Otherwise, recovering from such an error would be much more complicated.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.