如何在C中将数字与txt文件中的字符串分开?

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

txt 文件:

44.56 john doe  
100.21 jane doe

如何计算数字的总和?这个函数给出 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;
}

只需告诉 fscanf 忽略 namesurname 槽,如下所示:

double get_sum(FILE *out) {
    double sum = 0;
    double value;

    while (fscanf(out, "%lf%*s%*s", &value) != EOF) {
        sum += value;
    }
    return sum;
}

问题在于您将指针传递给 char 而不是传递给可以保存内容的 char array 的指针。因为你没有它溢出并导致未定义的行为。

但是如果你真的想也读入名字然后尝试:

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;
}

此处缓冲区的长度刚好足以容纳示例文本文件数据。在现实生活中(如果你需要的话)你会有足够大的空间来处理最长的名字。与原始代码的重要区别在于 namesurnamefscanf 函数期望的指针。

但是考虑到名称有时长度是不可预测的,在读取该行的值后,只需将剩余的行读入缓冲区并忽略它即可。

#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);
}

text.txt 个文件包含

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

运行 最后一个程序应该产生类似于

的模拟
Sum is 10.630000

在行

while(fscanf(out, "%lf %s %s", &value, name, surname) != EOF)

函数fscanf的return值与EOF比较不好。例如,如果该函数只能匹配一个参数,那么它将 return 1,但您的程序仍然会表现得好像所有 3 个参数都已匹配,并且您的程序将尝试处理 non-existant 数据。因此,您应该改为编写以下内容:

while( fscanf(out, "%lf %s %s", &value, name, surname) == 3 )

但是,这可能不是您遇到的直接问题的原因。该问题可能是由于 %s 转换格式说明符需要写入指针这一事实。但是,您传递的是单个 char.

的值(不是指针)

假设您启用了警告,您的编译器应该已经就此警告过您。有关详细信息,请参阅此问题:

为了解决这个问题,你应该改变行

char name;
char surname;

至:

char name[50];
char surname[50];

此外,您可能应该限制写入这些字符串的字符数,以防止 buffer overflow,如下所示:

while( fscanf(out, "%lf %49s %49s", &value, name, surname) == 3 )

对于line-based输入,我一般建议你一次读取一行,每行使用函数fgets. You can then use the function sscanf,以便解析它。

如果您像现在一样使用 fscanf,并且它不完全匹配一行中的 3 个字段,那么解析器将与这些行不同步,并且不会能够在新行的开头重新同步自身,这可能意味着您的程序将对文件的其余部分行为不正常,而不仅仅是对一行行为不正常。

这是一个使用 fgetssscanf 的程序:

#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 );
}

随着输入

44.56 john doe
100.21 jane doe

根据问题,这个程序有以下输出:

The sum is: 144.770000

如果您现在改为向程序提供包含一行无效输入的输入

44.56 john doe
invalid_input_line
100.21 jane doe

它只会在解析该无效行时失败,但仍会正确处理其他行:

WARNING: skipping line due to parse failure!
The sum is: 144.770000

如前所述,您的程序能够从该错误中恢复,因为它使用 fgets 一次读取一行,并且使用 sscanf 而不是 fscanf .否则,从这样的错误中恢复会复杂得多。