从文件 w/period 中读取数字(整数和小数)作为分隔符
Reading Numbers (integers and decimals) from file w/period as delimiter
目前,我想获取带有分隔符 .
的文件。但是,使用fscanf无法区分小数和整数。
想要提取前两个整数(由 .
分隔)和最后的小数到 tmp[]
尝试 fscanf(file,
"%d.", &tmp[j]);
与 %d
、%d.
和 %f
,都没有用。
%d
的结果:tmp[3]: {1.61149323e-43, 0, 0.409999996}
%d.
的结果:tmp[3]: {1.61149323e-43, 5.7453237e-44, 24.3600006}
%f
的结果:tmp[3]: {115.410004, 24.3600006, 113.489998}
%d
和 %d.
[0] 和 [1] 出现乱码,只有 %d.
[3] 似乎没看错。
%f
看起来不错,但它把前两个数字融合成一位小数。
我必须使用 fgets()
还是 fgetc()
?或者我可以更改 fscanf()
格式说明符以使其正确?
预期结果:(在调试器中)
tmp[0]: 115
tmp[1]: 41
tmp[2]: 24.36
(file line 2 as input)
tmp[0]: 113
tmp[1]: 49
tmp[2]: 44
来源:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *file = fopen("data.txt", "r");
float tmp[3] = {};
for(int j = 0; j < 2; j++) {
fscanf(file, "%d.", &tmp[j]);
}
fscanf(file, "%f", &tmp[2]);
}
Data.txt
115.41.24.360
113.49.44
115.41.51.573
%d
转换规范用于读取十进制整数,需要一个 int *
参数。同样,%i
、%o
、%u
、%x
和 %X
转换规范也适用于整数。
使用%f
是行不通的;它会将 'second integer' 读取为第一个 floating-point 值的小数部分,并且没有办法阻止它这样做(除非你可以安全地使用 %3f
因为总会有大多数 3 位数——这是一个可疑的命题。
您需要使用
int i1, i2;
if (fscanf(file, "%d.%d.%f", &i1, &i2, &tmp[2]) != 3)
{
…handle error…
}
tmp[0] = i1;
tmp[1] = i2;
这会将整数值读入 int
变量,然后将结果分配给 float
数组元素。请注意,您应该始终检查 fscanf()
和朋友的 return 值。如果它不是你所期望的,那就有问题(只要你的期望是正确的,一旦你经常阅读 fscanf()
的规范,它们就会是这样——第一次每天几次几天,下周每天一次,下个月每周一次,明年大约每月一次)。
每当您必须将多种类型作为单个对象处理时,您应该考虑 struct
提供存储。这里有两个整数和一个要存储的浮点数。允许这样做的简单结构是:
typedef struct { /* struct to hold data from line */
int n1, n2;
float f;
} twointf;
typedef
是为了方便,让您可以引用 twointf
作为类型,而不是每次都重复 struct twointf
。使用结构,您现在可以声明一个简单的 twointf
数组来处理所需数量的数组。
要读取数据,使用 fgets()
将整行读入足够大小的缓冲区(字符数组)并使用 sscanf()
进行解析总是优于使用 [=21= 直接读取].如果您的数据文件中有错误,fgets()
会将整行读入缓冲区,错误只会影响单行数据。使用 fscanf()
可能会发生 Matching-Failure,或者您的读取将换行到下一行,其中省略的值会破坏您从该点向前读取的文件。
要用 fgets()
阅读并用 sscanf()
分开,你可以这样做:
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define MAXS 32
...
char buf[MAXC]; /* read buffer for line */
size_t ndx = 0; /* array of struct index */
twointf arr[MAXS] = {{ .n1 = 0 }}; /* array of struct */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
...
/* while array not full, read line */
while (ndx < MAXS && fgets (buf, MAXC, fp)) {
if (sscanf (buf, "%d.%d.%f", /* separate into 2 int and float */
&arr[ndx].n1, &arr[ndx].n2, &arr[ndx].f) == 3) {
ndx++; /* on success, increment index */
}
}
仅此而已。读取您的数据,使用 sscanf()
进行转换以验证 return 并且仅在成功转换所有值时递增数组索引。
总而言之,你可以做到:
#include <stdio.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define MAXS 32
typedef struct { /* struct to hold data from line */
int n1, n2;
float f;
} twointf;
int main (int argc, char **argv) {
char buf[MAXC]; /* read buffer for line */
size_t ndx = 0; /* array of struct index */
twointf arr[MAXS] = {{ .n1 = 0 }}; /* array of struct */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
/* while array not full, read line */
while (ndx < MAXS && fgets (buf, MAXC, fp)) {
if (sscanf (buf, "%d.%d.%f", /* separate into 2 int and float */
&arr[ndx].n1, &arr[ndx].n2, &arr[ndx].f) == 3) {
ndx++; /* on success, increment index */
}
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
for (size_t i = 0; i < ndx; i++) /* output results */
printf ("\narr[%zu].n1 = %d\narr[%zu].n2 = %d\narr[%zu].f = %.2f\n",
i, arr[i].n1, i, arr[i].n2, i, arr[i].f);
}
例子Use/Output
使用 dat/data_int_float.txt
中的示例数据,您将:
$ ./bin/twointf dat/data_int_float.txt
arr[0].n1 = 115
arr[0].n2 = 41
arr[0].f = 24.36
arr[1].n1 = 113
arr[1].n2 = 49
arr[1].f = 44.00
arr[2].n1 = 115
arr[2].n2 = 41
arr[2].f = 51.57
(如果存在小数数据,您可以使用 %g
格式说明符 floating-point 仅输出小数位 - 由您决定)
目前,我想获取带有分隔符 .
的文件。但是,使用fscanf无法区分小数和整数。
想要提取前两个整数(由 .
分隔)和最后的小数到 tmp[]
尝试 fscanf(file,
"%d.", &tmp[j]);
与 %d
、%d.
和 %f
,都没有用。
%d
的结果:tmp[3]: {1.61149323e-43, 0, 0.409999996}
%d.
的结果:tmp[3]: {1.61149323e-43, 5.7453237e-44, 24.3600006}
%f
的结果:tmp[3]: {115.410004, 24.3600006, 113.489998}
%d
和 %d.
[0] 和 [1] 出现乱码,只有 %d.
[3] 似乎没看错。
%f
看起来不错,但它把前两个数字融合成一位小数。
我必须使用 fgets()
还是 fgetc()
?或者我可以更改 fscanf()
格式说明符以使其正确?
预期结果:(在调试器中)
tmp[0]: 115
tmp[1]: 41
tmp[2]: 24.36
(file line 2 as input)
tmp[0]: 113
tmp[1]: 49
tmp[2]: 44
来源:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *file = fopen("data.txt", "r");
float tmp[3] = {};
for(int j = 0; j < 2; j++) {
fscanf(file, "%d.", &tmp[j]);
}
fscanf(file, "%f", &tmp[2]);
}
Data.txt
115.41.24.360
113.49.44
115.41.51.573
%d
转换规范用于读取十进制整数,需要一个 int *
参数。同样,%i
、%o
、%u
、%x
和 %X
转换规范也适用于整数。
使用%f
是行不通的;它会将 'second integer' 读取为第一个 floating-point 值的小数部分,并且没有办法阻止它这样做(除非你可以安全地使用 %3f
因为总会有大多数 3 位数——这是一个可疑的命题。
您需要使用
int i1, i2;
if (fscanf(file, "%d.%d.%f", &i1, &i2, &tmp[2]) != 3)
{
…handle error…
}
tmp[0] = i1;
tmp[1] = i2;
这会将整数值读入 int
变量,然后将结果分配给 float
数组元素。请注意,您应该始终检查 fscanf()
和朋友的 return 值。如果它不是你所期望的,那就有问题(只要你的期望是正确的,一旦你经常阅读 fscanf()
的规范,它们就会是这样——第一次每天几次几天,下周每天一次,下个月每周一次,明年大约每月一次)。
每当您必须将多种类型作为单个对象处理时,您应该考虑 struct
提供存储。这里有两个整数和一个要存储的浮点数。允许这样做的简单结构是:
typedef struct { /* struct to hold data from line */
int n1, n2;
float f;
} twointf;
typedef
是为了方便,让您可以引用 twointf
作为类型,而不是每次都重复 struct twointf
。使用结构,您现在可以声明一个简单的 twointf
数组来处理所需数量的数组。
要读取数据,使用 fgets()
将整行读入足够大小的缓冲区(字符数组)并使用 sscanf()
进行解析总是优于使用 [=21= 直接读取].如果您的数据文件中有错误,fgets()
会将整行读入缓冲区,错误只会影响单行数据。使用 fscanf()
可能会发生 Matching-Failure,或者您的读取将换行到下一行,其中省略的值会破坏您从该点向前读取的文件。
要用 fgets()
阅读并用 sscanf()
分开,你可以这样做:
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define MAXS 32
...
char buf[MAXC]; /* read buffer for line */
size_t ndx = 0; /* array of struct index */
twointf arr[MAXS] = {{ .n1 = 0 }}; /* array of struct */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
...
/* while array not full, read line */
while (ndx < MAXS && fgets (buf, MAXC, fp)) {
if (sscanf (buf, "%d.%d.%f", /* separate into 2 int and float */
&arr[ndx].n1, &arr[ndx].n2, &arr[ndx].f) == 3) {
ndx++; /* on success, increment index */
}
}
仅此而已。读取您的数据,使用 sscanf()
进行转换以验证 return 并且仅在成功转换所有值时递增数组索引。
总而言之,你可以做到:
#include <stdio.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define MAXS 32
typedef struct { /* struct to hold data from line */
int n1, n2;
float f;
} twointf;
int main (int argc, char **argv) {
char buf[MAXC]; /* read buffer for line */
size_t ndx = 0; /* array of struct index */
twointf arr[MAXS] = {{ .n1 = 0 }}; /* array of struct */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
/* while array not full, read line */
while (ndx < MAXS && fgets (buf, MAXC, fp)) {
if (sscanf (buf, "%d.%d.%f", /* separate into 2 int and float */
&arr[ndx].n1, &arr[ndx].n2, &arr[ndx].f) == 3) {
ndx++; /* on success, increment index */
}
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
for (size_t i = 0; i < ndx; i++) /* output results */
printf ("\narr[%zu].n1 = %d\narr[%zu].n2 = %d\narr[%zu].f = %.2f\n",
i, arr[i].n1, i, arr[i].n2, i, arr[i].f);
}
例子Use/Output
使用 dat/data_int_float.txt
中的示例数据,您将:
$ ./bin/twointf dat/data_int_float.txt
arr[0].n1 = 115
arr[0].n2 = 41
arr[0].f = 24.36
arr[1].n1 = 113
arr[1].n2 = 49
arr[1].f = 44.00
arr[2].n1 = 115
arr[2].n2 = 41
arr[2].f = 51.57
(如果存在小数数据,您可以使用 %g
格式说明符 floating-point 仅输出小数位 - 由您决定)