[英]How can I read only the integer values from a txt file into an array?
我正在修改我编写的一些现有代码,以从.txt
文件中获取电阻和电流值并计算电压解决方案。 让我感到困惑的是,一旦我读入一行并使用strtok
将整数与其他文本分开,我不知道如何将这些值正确保存到某些变量中,然后我可以将其插入数组。
这是从文本文件中读入的示例行:
R3:56.0, R1:33.0, R2:47.0, R4:68.0, R5:75.0, IA:10.0, IB:110.0
我下面的代码采用该行并输出:
R3
56.0
R1
33.0
R2
47.0
R4
68.0
R5
75.0
IA
10.0
IB
110.0
我的下一个目标是以某种方式识别R3 = 56.0
和R1 = 33.0
等等,将这些值存储到名为R1
、 R2
、 R3
、 R4
、 R5
、 I1
、 I2
变量中,以便我稍后可以在我的代码中使用它们。
#include <stdio.h>
#include <string.h>
#define LINEMAX 100
int main()
{
FILE *dataPtr;
char line[LINEMAX];
char* token;
float R1 ,R2, R3, R4, R5, I1, I2;
double A[4][5];
int i = 0;
if((dataPtr = fopen("input.txt" , "r")) == NULL)
{
fprintf(stderr , "FILE NOT FOUND!");
}
while (fgets(line, LINEMAX, dataPtr) != NULL)
{
token = strtok (line, ",:");
while (token != NULL)
{
printf("%s\n" , token);
token = strtok (NULL, ",:");
}
}
fclose(dataPtr);
这里有一些建议可以帮助您将每一行解析为您需要的值。 而不是 7 个单独的变量, R1, R2, R3, R4, R5, I1, I2
,只需声明一个double
数组(使用float
只会引入更多的舍入误差,并且并没有真正节省现代处理器的速度) . (例如存储你的值,以便在阵列中R1
在索引0
, R2
在索引1
,依此类推)。 这样,如果您有多行相同的数据,只需将 7 个元素的临时数组和一个memcpy
填充到它们的数组中即可。
您已经很好地使用了LINEMAX
的#define
来避免在整个代码中散布魔术数字。 你也可以对字符串常量做同样的事情,例如
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define TOKLEN 32 /* size for temporary token storage */
#define NELEM 7 /* number of elements to separate (R1-5, IA, IB) */
#define DELIM ",\n" /* delimiter for strtok */
在解析您的数据行时,您需要将诸如"R1"
类的字符串映射到索引,并且需要一种将索引映射到字符串的方法(因此您可以反向操作)。 当映射数量很少时,像这里这样的一个方便的方法就是使用enum
和指针数组来字符串文字,例如
/* enum for mapping names to index */
enum { R1, R2, R3, R4, R5, IA, IB };
/* array for mapping index to names */
const char *id[] = { "R1", "R2", "R3", "R4", "R5", "IA", "IB" };
这只是避免在整个代码中散布字符串文字以及提供让您避免的映射的另一种方法,例如
if (strcmp (tmp, "R1") == 0)
a[R1] = d;
else if (strcmp (tmp, "R2") == 0)
a[R2] = d;
...
并且,改为使用以下内容,将id
的单一定义保留在顶部,作为将来更改字符串映射时必须更改的唯一位置,例如
if (strcmp (tmp, id[R1]) == 0)
a[R1] = d;
else if (strcmp (tmp, id[R2]) == 0)
a[R2] = d;
...
为了将值解析为相应的数组索引,您只需将每一行读入缓冲区,用strtok
标记该行以获得逗号分隔值,然后在标记上使用sscanf
来解析每个行的名称和值令牌,例如
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line */
...
while (fgets (buf, MAXC, fp)) { /* read each line into buf */
char tmp[TOKLEN]; /* temporary storage for R3, etc.. */
double d, a[NELEM] = {0.}; /* temporary double and array */
/* tokenize line */
for (char *p = strtok(buf, DELIM); p; p = strtok(NULL, DELIM)) {
/* separate token into tmp string and double value in array */
if (sscanf (p, " %31[^:]:%lf", tmp, &d) != 2) {
fputs ("error: bad token format\n", stderr);
goto nextline; /* goto steps over code to process full arr */
}
... /* compare tmp value here and store in-order in array */
}
... /* handle whatever additional processing on array needed here */
nextline:; /* label for nextline */
}
(注意: a[NELEM] = {0.};
数组初始化为零,因此如果由于某种原因一行缺少值,则不会调用未定义的行为尝试访问未初始化的值)
/* compare tmp value ... */
逻辑上面的位置就是:
/* compare value in tmp store in-order in array */
if (strcmp (tmp, id[R1]) == 0)
a[R1] = d;
else if (strcmp (tmp, id[R2]) == 0)
a[R2] = d;
else if (strcmp (tmp, id[R3]) == 0)
a[R3] = d;
else if (strcmp (tmp, id[R4]) == 0)
a[R4] = d;
else if (strcmp (tmp, id[R5]) == 0)
a[R5] = d;
else if (strcmp (tmp, id[IA]) == 0)
a[IA] = d;
else if (strcmp (tmp, id[IB]) == 0)
a[IB] = d;
else {
fputs ("error: unrecognized format.\n", stderr);
goto nextline;
}
对于进一步的处理,例如我们只是按顺序输出值,例如
for (int i = 0; i < NELEM; i++) /* output line results */
printf ("got %s = %.2f\n", id[i], a[i]);
一个简短的示例,它采用您的输入行并将双R1-5, IA, IB
值按R1-5, IA, IB
的顺序完全分离到一个数组中:
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define TOKLEN 32 /* size for temporary token storage */
#define NELEM 7 /* number of elements to separate (R1-5, IA, IB) */
#define DELIM ",\n" /* delimiter for strtok */
/* enum for mapping names to index */
enum { R1, R2, R3, R4, R5, IA, IB };
/* array for mapping index to names */
const char *id[] = { "R1", "R2", "R3", "R4", "R5", "IA", "IB" };
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line */
/* 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 (fgets (buf, MAXC, fp)) { /* read each line into buf */
char tmp[TOKLEN]; /* temporary storage for R3, etc.. */
double d, a[NELEM] = {0.}; /* temporary double and array */
/* tokenize line */
for (char *p = strtok(buf, DELIM); p; p = strtok(NULL, DELIM)) {
/* separate token into tmp string and double value in array */
if (sscanf (p, " %31[^:]:%lf", tmp, &d) != 2) {
fputs ("error: bad token format\n", stderr);
goto nextline; /* goto steps over code to process full arr */
}
/* compare value in tmp store in-order in array */
if (strcmp (tmp, id[R1]) == 0)
a[R1] = d;
else if (strcmp (tmp, id[R2]) == 0)
a[R2] = d;
else if (strcmp (tmp, id[R3]) == 0)
a[R3] = d;
else if (strcmp (tmp, id[R4]) == 0)
a[R4] = d;
else if (strcmp (tmp, id[R5]) == 0)
a[R5] = d;
else if (strcmp (tmp, id[IA]) == 0)
a[IA] = d;
else if (strcmp (tmp, id[IB]) == 0)
a[IB] = d;
else {
fputs ("error: unrecognized format.\n", stderr);
goto nextline;
}
}
for (int i = 0; i < NELEM; i++) /* output line results */
printf ("got %s = %.2f\n", id[i], a[i]);
nextline:; /* label for nextline */
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
return 0;
}
示例使用/输出
使用文件dat/rnumval.txt
的输入行,您将收到:
$ ./bin/readrnumval dat/rnumval.txt
got R1 = 33.00
got R2 = 47.00
got R3 = 56.00
got R4 = 68.00
got R5 = 75.00
got IA = 10.00
got IB = 110.00
这只是方便地将单独的值映射到数组中的可识别索引的一种方式,允许您映射名称和索引。 (这就是为什么我建议将您的姓名和文字与输入中的数据保持匹配,例如IA, IB
而不是I1, I2
由您决定,只需更多工作)
仔细检查一下,如果您还有其他问题,请告诉我。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.