用C语言中的fscanf textfile.txt定义变量
我有一个textfile.txt,逐行包含变量定义,例如长度=1.1m 使用用C语言中的fscanf textfile.txt定义变量,c,scanf,C,Scanf,我有一个textfile.txt,逐行包含变量定义,例如长度=1.1m 使用fscanf我想将值1.1存储在变量double length中 有人能给我一些提示,在这种情况下如何使用fscanf有一个“=”分隔符吗 提前谢谢 编辑: 下面是一个示例性inputfile.txt,显示其结构: [elements] Number of elements = 2 length_1 = 1.5m length_2 = 2.1m velocity_1 = 0.35m/s velocity_2 = 0.11
fscanf
我想将值1.1存储在变量double length
中
有人能给我一些提示,在这种情况下如何使用fscanf有一个“=”分隔符吗
提前谢谢
编辑:
下面是一个示例性inputfile.txt,显示其结构:
[elements]
Number of elements = 2
length_1 = 1.5m
length_2 = 2.1m
velocity_1 = 0.35m/s
velocity_2 = 0.11m/s
[cells]
Number of cells = 2
cell_1 = 0.0m
cell_2 = 1.3m
我想将这两个部分的参数提取到两个不同的结构中。读取格式化文件的简单程序:
#include <stdio.h>
int main(void) {
FILE *fp = fopen("data.txt", "r");
float length;
if (fp == NULL) {
printf("The file was failed to open.\n");
return -1;
}
while (fscanf(fp, "%*s %*s %f", &length) == 1)
printf("%f", length);
return 0;
}
format%*s
字符串将跳过该单词的读取
文件data.txt
看起来像:
length = 5.324325m
然后,您将获得以下输出:
5.324325
您现在可以清楚地看到字符串被截断,并且成功地将值分配给变量。假设您的文本文件如下所示:
length = 1.2m
length = 3.4m
length = 12.4m
然后,您可以使用以下代码阅读:
FILE* filePtr = fopen("textfile.txt","r");
if (filePtr==NULL)
{
printf("no such file.");
return 0;
}
float num;
while (fscanf(filePtr,"length = %f", &num)==1)
printf("%f\n", num);
fclose(filePtr);
有关从文件中读取的更多信息,请勾选此项。这里有一种方法,可以按任意顺序给出两个部分,或者只能给出一个部分,甚至没有:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Element {
double length;
double velocity;
} Element;
void * read_section(FILE * fp, const char * what, int * n, size_t sz)
{
if (*n != 0) {
fprintf(stderr, "invalid file, several sections [%s]\n", what);
exit(-1);
}
char fmt[64];
sprintf(fmt, " Number of %s = %%d", what); /* notice space at beginning */
if (fscanf(fp, fmt, n) != 1) {
fprintf(stderr, "invalid file, expected 'Number of %s = <n>'\n", what);
exit(-1);
}
if (*n <= 0) {
fprintf(stderr, "number of %s must be > 0\n", what);
exit(-1);
}
void * r = malloc(*n * sz);
if (r == NULL) {
fprintf(stderr, "not enough memory for %d %s\n", *n, what);
exit(-1);
}
return r;
}
void read_var(FILE * fp, const char * var, const char * unity, int rank, double * v)
{
char fmt[64];
sprintf(fmt, " %s_%d = %%lg%s", var, rank, unity); /* notice space at beginning */
if (fscanf(fp, fmt, v) != 1) {
fprintf(stderr, "invalid file, expected '%s_%d = <val>%s'\n", var, rank, unity);
exit(-1);
}
}
int main(int argc, char ** argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", *argv);
exit(-1);
}
FILE * fp = fopen(argv[1], "r");
if (fp == NULL) {
perror("cannot open file");
exit(-1);
}
int nelts = 0;
Element * elts = NULL;
int ncells = 0;
double * cells = NULL;
char line[32];
int i;
while (fscanf(fp, " %31s", line) == 1) { /* notice space at beginning of format */
if (!strcmp(line, "[elements]")) {
elts = read_section(fp, "elements", &nelts, sizeof(*elts));
for (i = 0; i != nelts; ++i)
read_var(fp, "length", "m", i+1, &elts[i].length);
for (i = 0; i != nelts; ++i)
read_var(fp, "velocity", "m/s", i+1, &elts[i].velocity);
}
else if (!strcmp(line, "[cells]")) {
cells = read_section(fp, "cells", &ncells, sizeof(*cells));
for (i = 0; i != ncells; ++i)
read_var(fp, "cell", "m", i+1, &cells[i]);
}
else {
fputs("invalid file, section header expected\n", stderr);
exit(-1);
}
}
fclose(fp);
/* to check */
printf("%d elements:\n", nelts);
for (i = 0; i != nelts; ++i)
printf("%d) length=%g, velocity=%g\n", i, elts[i].length, elts[i].velocity);
printf("\n%d cells:", ncells);
for (i = 0; i != ncells; ++i)
printf(" %g", cells[i]);
putchar('\n');
free(elts);
free(cells);
return 0;
}
交换区段命令
pi@raspberrypi:/tmp $ cat f2
[cells]
Number of cells = 2
cell_1 = 0.0m
cell_2 = 1.3m
[elements]
Number of elements = 2
length_1 = 1.5m
length_2 = 2.1m
velocity_1 = 0.35m/s
velocity_2 = 0.11m/s
pi@raspberrypi:/tmp $ ./a.out f2
2 elements:
0) length=1.5, velocity=0.35
1) length=2.1, velocity=0.11
2 cells: 0 1.3
pi@raspberrypi:/tmp $
唯一元素
pi@raspberrypi:/tmp $ cat f3
[elements]
Number of elements = 2
length_1 = 1.5m
length_2 = 2.1m
velocity_1 = 0.35m/s
velocity_2 = 0.11m/s
pi@raspberrypi:/tmp $ ./a.out f3
2 elements:
0) length=1.5, velocity=0.35
1) length=2.1, velocity=0.11
0 cells:
pi@raspberrypi:/tmp $
只有细胞
pi@raspberrypi:/tmp $ cat f4
[cells]
Number of cells = 2
cell_1 = 0.0m
cell_2 = 1.3m
pi@raspberrypi:/tmp $ ./a.out f4
0 elements:
2 cells: 0 1.3
pi@raspberrypi:/tmp $
空输入文件
pi@raspberrypi:/tmp $ ./a.out /dev/null
0 elements:
0 cells:
pi@raspberrypi:/tmp $
更多元素和单元
pi@raspberrypi:/tmp $ cat f
[elements]
Number of elements = 3
length_1 = 1.5m
length_2 = 2.1m
length_3 = 1.1m
velocity_1 = 0.35m/s
velocity_2 = 0.11m/s
velocity_3 = 0.33m/s
[cells]
Number of cells = 5
cell_1 = 0.0m
cell_2 = 1.3m
cell_3 = 2.3m
cell_4 = 3.3m
cell_5 = 4.3m
pi@raspberrypi:/tmp $ ./a.out f
3 elements:
0) length=1.5, velocity=0.35
1) length=2.1, velocity=0.11
2) length=1.1, velocity=0.33
5 cells: 0 1.3 2.3 3.3 4.3
pi@raspberrypi:/tmp $
检查可能出现的错误情况,我鼓励你不要认为一切都是好的,而要检查它
要在Linux/Unix下完成,请检查在valgrind下运行的程序,例如:
pi@raspberrypi:/tmp $ valgrind ./a.out f
==13981== Memcheck, a memory error detector
==13981== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==13981== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==13981== Command: ./a.out f
==13981==
3 elements:
0) length=1.5, velocity=0.35
1) length=2.1, velocity=0.11
2) length=1.1, velocity=0.33
5 cells: 0 1.3 2.3 3.3 4.3
==13981==
==13981== HEAP SUMMARY:
==13981== in use at exit: 0 bytes in 0 blocks
==13981== total heap usage: 5 allocs, 5 frees, 5,560 bytes allocated
==13981==
==13981== All heap blocks were freed -- no leaks are possible
==13981==
==13981== For lists of detected and suppressed errors, rerun with: -s
==13981== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
pi@raspberrypi:/tmp $
是的,不要使用
fscanf()
。使用fgets()
和strtok()
以及最后的sscanf()
或strtod()
。如果表单总是像length=1.1m
那样,这意味着变量是一个单词(一个没有空格或制表符的字符串,换行符..),然后是一个空格,然后是=,然后是一个值,最后是一个单词。因此,fscanf
的格式很明显,您无法将字符串“length”
转换为变量名。您必须已经有一个同名的,或者,用id名称和值构建一个struct
。如果您也有类似于“width=2.3m”
的定义,那么您可能希望将数据提取到其他特定变量或数组中。无论如何,这个问题的定义太宽泛了。谢谢@bruno,我现在可以使用:fscanf(file,“%*s%*s%s”,word)==1
,word是“``word=char[100]”,从而提取出值+单位。是否有一种方法可以省略单位(我有不同单位的变量,例如m,m/s,…),除了“var”名称可以包含空格之外,表单仍然是=
,您可以管理它。如果您想要一个完全有效的解决方案,您需要解释在您的输入文件中可以找到的所有内容,以及您想要提取/保存的内容,编辑您的问题,然后给出一个解决方案,同时保存var名称和unity,另一个即使在“=”之前没有空格也可以工作?假设在值之前总是length=
,这是一个很大的假设…@bruno我假设文件是理想的,并且是我在第一个答案中所说的形式(为了保持答案的简单性),但是你是对的,对于我来说,在“完美”文件之外,我们应该注意这一点。你不能假设var名称总是“length”,因为该语句涉及变量定义
(复数)。因此,我鼓励您编辑您的答案,并根据您对文件内容所做的相关假设,提出其他方法。另外,OP想要一个double
而不是float
hanks,感谢迄今为止给出建议的所有人,太好了!我已经编辑了上面的原始问题,显示了一个示例性的inputfile.txt。注意,对于变量,我有不同的部分和两种类型的格式。我能否以某种方式过滤[elements]部分中的fscanf行,然后将这些值存储在我的struct元素中,然后转到[cells]部分并执行相同的操作?
pi@raspberrypi:/tmp $ cat f
[elements]
Number of elements = 3
length_1 = 1.5m
length_2 = 2.1m
length_3 = 1.1m
velocity_1 = 0.35m/s
velocity_2 = 0.11m/s
velocity_3 = 0.33m/s
[cells]
Number of cells = 5
cell_1 = 0.0m
cell_2 = 1.3m
cell_3 = 2.3m
cell_4 = 3.3m
cell_5 = 4.3m
pi@raspberrypi:/tmp $ ./a.out f
3 elements:
0) length=1.5, velocity=0.35
1) length=2.1, velocity=0.11
2) length=1.1, velocity=0.33
5 cells: 0 1.3 2.3 3.3 4.3
pi@raspberrypi:/tmp $
pi@raspberrypi:/tmp $ valgrind ./a.out f
==13981== Memcheck, a memory error detector
==13981== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==13981== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==13981== Command: ./a.out f
==13981==
3 elements:
0) length=1.5, velocity=0.35
1) length=2.1, velocity=0.11
2) length=1.1, velocity=0.33
5 cells: 0 1.3 2.3 3.3 4.3
==13981==
==13981== HEAP SUMMARY:
==13981== in use at exit: 0 bytes in 0 blocks
==13981== total heap usage: 5 allocs, 5 frees, 5,560 bytes allocated
==13981==
==13981== All heap blocks were freed -- no leaks are possible
==13981==
==13981== For lists of detected and suppressed errors, rerun with: -s
==13981== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
pi@raspberrypi:/tmp $