How to separate numbers from strings in txt file in C?

Solution 1:

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.