如何在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
忽略 name
和 surname
槽,如下所示:
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;
}
此处缓冲区的长度刚好足以容纳示例文本文件数据。在现实生活中(如果你需要的话)你会有足够大的空间来处理最长的名字。与原始代码的重要区别在于 name
和 surname
是 fscanf
函数期望的指针。
但是考虑到名称有时长度是不可预测的,在读取该行的值后,只需将剩余的行读入缓冲区并忽略它即可。
#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 个字段,那么解析器将与这些行不同步,并且不会能够在新行的开头重新同步自身,这可能意味着您的程序将对文件的其余部分行为不正常,而不仅仅是对一行行为不正常。
这是一个使用 fgets
和 sscanf
的程序:
#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
.否则,从这样的错误中恢复会复杂得多。
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
忽略 name
和 surname
槽,如下所示:
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;
}
此处缓冲区的长度刚好足以容纳示例文本文件数据。在现实生活中(如果你需要的话)你会有足够大的空间来处理最长的名字。与原始代码的重要区别在于 name
和 surname
是 fscanf
函数期望的指针。
但是考虑到名称有时长度是不可预测的,在读取该行的值后,只需将剩余的行读入缓冲区并忽略它即可。
#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 个字段,那么解析器将与这些行不同步,并且不会能够在新行的开头重新同步自身,这可能意味着您的程序将对文件的其余部分行为不正常,而不仅仅是对一行行为不正常。
这是一个使用 fgets
和 sscanf
的程序:
#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
.否则,从这样的错误中恢复会复杂得多。