虽然是一个较老的问题,但值得回答。您没有获得datacycle 和datevalid 的有效数据的原因是您尝试使用转换为int 来读取的输入超出了可表示为int 的值。例如200507011200 超过有符号整数表示的最大值两个数量级。
但是,简单地使用更大的存储类型来容纳这些值将导致以后难以分离字符串的年、月、日、时间部分。更好的方法是将datacycle 和datevalid 读取为字符串。如果需要,您可以稍后转换为数值,或者更有可能将其转换为年、月、日、时间。
此外,直接使用fscanf() 读取输入文件是一种脆弱的方法。一行格式的单个错误将破坏从该点向前读取的所有数据。
相反,将每一行读入缓冲区(字符数组),然后使用sscanf() 解析成单独的值,从而将读取和转换解耦,从而允许完全读取每一行。在这种情况下,如果一行包含无效字符等...只有该行中的值解析会失败,并且可以正确读取所有剩余的行。
不要使用 MagicNumbers 或硬编码文件名。相反,要么提供文件名作为程序的第一个参数(这就是 main() 的 int argc, char **argv 参数),要么提示用户并将文件名作为输入。你不应该仅仅为了从不同的文件名读取数据而重新编译你的代码。 30 在您的代码中是一个 MagicNumber。如果你需要一个常量,#define 一个或者使用一个全局的enum。例如:
#define MAXC 1024 /* if you need a constant, #define on (or more) */
#define MAXVL 32
#define NELEM 16
其中MAXC 是从每行读取的最大字符数(例如,保存该行的字符数组的大小),MAXVL 的大小为 var 和 level 和 NELEM数组中用于保存所有值的元素数量和16 的一般常量,也用于datacycle 和datevalid 存储的字符串大小。
要保存每行数据以便您的程序可以处理它,请创建一个结构来保存 loc、var、level、datacycle、datevalid 和 @987654349 的值@,并简单地声明一个结构数组。这样,当您读取和转换每一行时,您可以将值存储在一个数组中以供整个程序使用,例如
typedef struct { /* store datacycle & datevalid as strings */
char var[MAXVL], level[MAXVL], datacycle[NELEM], datevalid[NELEM];
int loc;
float value;
} mydata_type;
将要读取的文件名作为程序的第一个参数(如果没有给出值,则默认从stdin 读取),您可以执行以下操作:
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line */
size_t n = 0; /* array element counter */
mydata_type arr[NELEM] = {{ .var = "" }}; /* 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;
}
您可以读取和存储每一行,直到您的数组已满或到达文件末尾,方法是将每一行循环并读取到buf,然后如上所述用sscanf() 分隔值,例如
/* while array not full and line read */
while (n < NELEM && fgets (buf, MAXC, fp)) {
mydata_type tmp; /* temporary structure to parse data into */
/* parse data from buf into temporary struct and VALIDATE */
if (sscanf (buf, "%d %s %s %s %s %f", &tmp.loc, tmp.var, tmp.level,
tmp.datacycle, tmp.datevalid, &tmp.value) == 6) {
arr[n] = tmp; /* on success, assign to array element */
n += 1; /* increment element counter */
}
else {
fputs ("error: invalid line format.\n", stderr);
}
}
完成后关闭文件,然后使用程序中需要的数据。例如,您可以输出从每一行读取的每个值,同时使用sscanf() 将datacycle 和datevalid 转换为年、月、日和时间。一个例子是:
void prn_mydata (mydata_type *arr, size_t n)
{
for (size_t i = 0; i < n; i++) {
int mc, dc, yc, tc, /* integer values for datacycle components */
mv, dv, yv, tv; /* integer values for datevalid components */
/* parse string values for datacycle & datevalid into components */
if (sscanf (arr[i].datacycle, "%4d%2d%2d%4d", &yc, &mc, &dc, &tc) != 4)
return;
if (sscanf (arr[i].datevalid, "%4d%2d%2d%4d", &yv, &mv, &dv, &tv) != 4)
return;
/* output results */
printf ("\n%d\n%s\n%s\n%s %d-%02d-%02d:%d\n"
"%s %d-%02d-%02d:%d\n%.3f\n",
arr[i].loc, arr[i].var, arr[i].level,
arr[i].datacycle, yc, mc, dc, tc,
arr[i].datevalid, yv, mv, dv, tv,
arr[i].value);
}
}
将其完全放入您将拥有的示例程序中:
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define on (or more) */
#define MAXVL 32
#define NELEM 16
typedef struct { /* store datacycle & datevalid as strings */
char var[MAXVL], level[MAXVL], datacycle[NELEM], datevalid[NELEM];
int loc;
float value;
} mydata_type;
void prn_mydata (mydata_type *arr, size_t n)
{
for (size_t i = 0; i < n; i++) {
int mc, dc, yc, tc, /* integer values for datacycle components */
mv, dv, yv, tv; /* integer values for datevalid components */
/* parse string values for datacycle & datevalid into components */
if (sscanf (arr[i].datacycle, "%4d%2d%2d%4d", &yc, &mc, &dc, &tc) != 4)
return;
if (sscanf (arr[i].datevalid, "%4d%2d%2d%4d", &yv, &mv, &dv, &tv) != 4)
return;
/* output results */
printf ("\n%d\n%s\n%s\n%s %d-%02d-%02d:%d\n"
"%s %d-%02d-%02d:%d\n%.3f\n",
arr[i].loc, arr[i].var, arr[i].level,
arr[i].datacycle, yc, mc, dc, tc,
arr[i].datevalid, yv, mv, dv, tv,
arr[i].value);
}
}
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line */
size_t n = 0; /* array element counter */
mydata_type arr[NELEM] = {{ .var = "" }}; /* 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 and line read */
while (n < NELEM && fgets (buf, MAXC, fp)) {
mydata_type tmp; /* temporary structure to parse data into */
/* parse data from buf into temporary struct and VALIDATE */
if (sscanf (buf, "%d %s %s %s %s %f", &tmp.loc, tmp.var, tmp.level,
tmp.datacycle, tmp.datevalid, &tmp.value) == 6) {
arr[n] = tmp; /* on success, assign to array element */
n += 1; /* increment element counter */
}
else {
fputs ("error: invalid line format.\n", stderr);
}
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
prn_mydata (arr, n); /* print the results */
}
使用/输出示例
使用dat/sourcefile.txt 中的示例数据,您将使用该程序并接收以下输出,其中该行的每个组件作为组的一部分打印在单独的行上:
$ ./bin/read_sourcefile dat/sourcefile.txt
222
MSLET[Pa]
0-MSL
200507011200 2005-07-01:1200
200507021200 2005-07-02:1200
101226.062
223
MSLET[Pa]
0-MSL
200507011200 2005-07-01:1200
200507021200 2005-07-02:1200
9999.000
224
MSLET[Pa]
0-MSL
200507011200 2005-07-01:1200
200507021200 2005-07-02:1200
101217.062
222
PRMSL[Pa]
0-MSL
200507011200 2005-07-01:1200
200507021200 2005-07-02:1200
101226.062
223
PRMSL[Pa]
0-MSL
200507011200 2005-07-01:1200
200507021200 2005-07-02:1200
9999.000
查看一下,如果您还有其他问题,请告诉我。