我对如何访问和更改结构的值感到困惑。该程序接收一些外部文件,并对每个字符串进行标记,然后将其归类为以下气候信息字段。外部文件如下所示:
TDV格式:
TN 1424325600000 dn20t1kz0xrz 67.0 0.0 0.0 0.0 101872.0 262.5665
TN 1422770400000 dn2dcstxsf5b 23.0 0.0 100.0 0.0 100576.0 277.8087
TN 1422792000000 dn2sdp6pbb5b 96.0 0.0 100.0 0.0 100117.0 278.49207
TN 1422748800000 dn2fjteh8e80 6.0 0.0 100.0 0.0 100661.0 278.28485
TN 1423396800000 dn2k0y7ffcup 14.0 0.0 100.0 0.0 100176.0 282.02142
这些列的顺序是,第一列用于状态代码,第二列用于时间戳记(自Unix时代以来的毫秒数),第三列是位置的geohash字符串(未使用),第四列是湿度百分比,第五个是雪(值0.0或1.0),第六个是云量百分比,第七个是雷击次数,第八个是压力(单位未知,但是数据没有用,所以没关系),第九个是表面温度(以开尔文为单位)。我确实意识到我必须转换时间戳记和表面温度,因此我对此并不担心。我需要汇总整个状态下的数据(与geohash无关),跟踪最低和最高温度以及它们发生的时间,并统计该状态的记录数,以便可以对值进行平均。
单个状态的输出应如下所示:
* Opening file: data_tn.tdv
* States found: TN
* -- State: TN --
* Number of Records: 17097
* Average Humidity: 49.4%
* Average Temperature: 58.3F
* Max Temperature: 110.4F on Mon Aug 3 11:00:00 2015
* Min Temperature: -11.1F on Fri Feb 20 04:00:00 2015
* Lightning Strikes: 781
* Records with Snow Cover: 107
* Average Cloud Cover: 53.0%
但是,会有多个状态,每个状态都有其自己的数据文件要处理。
如您所见,第一个令牌将分配给状态代码,但是我不知道如何执行此操作。我尝试了许多strcpy和许多其他方法来尝试将令牌发送到各自的字段中,但是没有一种有效。
struct climate_info
{
char code[3];
unsigned long num_records;
unsigned long timestamp;
char location[13];
unsigned int humidity;
int snow;
unsigned int cover;
int strikes;
long double pressure;
long double sum_temperature;
};
struct stats
{
char code[3];
long long timestamp;
double humidity;
double snow;
double cloud;
double strikes;
double sum_temperature;
}stats;
void analyze_file(FILE *file, struct climate_info *states[], int num_states);
void print_report(struct climate_info *states[], int num_states);
int main(int argc, char *argv[])
{
/* TODO: fix this conditional. You should be able to read multiple files. */
if (argc < 1 )
{
printf("Usage: %s tdv_file1 tdv_file2 ... tdv_fileN \n", argv[0]);
return EXIT_FAILURE;
}
/* Let's create an array to store our state data in. As we know, there are
* 50 US states. */
struct climate_info *states[NUM_STATES] = { NULL };
int i;
for (i = 1; i < argc; ++i)
{
/* TODO: Open the file for reading */
/* TODO: If the file doesn't exist, print an error message and move on
* to the next file. */
/* TODO: Analyze the file */
/* analyze_file(file, states, NUM_STATES); */
FILE *fp = fopen(argv[i], "r");
if(fp == NULL)
{
printf("Error opening file");
break;
}
else if(fp)
{
analyze_file(fp, states,NUM_STATES);
}
fclose(fp);
}
print_report(states, NUM_STATES);
return 0;
}
void analyze_file(FILE *file, struct climate_info **states, int num_states)
{
const int line_sz = 100;
char line[line_sz];
int counter = 0;
char *token;
while (fgets(line, line_sz, file) != NULL)
{
/* TODO: We need to do a few things here:
*
* * Tokenize the line.
* * Determine what state the line is for. This will be the state
* code, stored as our first token.
* * If our states array doesn't have a climate_info entry for
* this state, then we need to allocate memory for it and put it
* in the next open place in the array. Otherwise, we reuse the
* existing entry.
* * Update the climate_info structure as necessary.
*/
struct climate_info *y = malloc(sizeof(struct climate_info)*num_states);
token = strtok(line," \t");
strcpy((y[counter]).code,token);
counter++;
printf("%s\n",token);
while(token)
{
printf("token: %s\n", token);
token = strtok(NULL, " \t");
}
printf("%d\n",counter);
//free(states);
}
void print_report(struct climate_info *states[], int num_states)
{
printf("States found: ");
int i;
for (i = 0; i < num_states; ++i) {
if (states[i] != NULL)
{
struct climate_info *info = states[i];
printf("%s", info->code);
}
}
printf("\n");
答案 0 :(得分:1)
从文件中读取的值不应直接分配给结构的元素。您需要一组变量(它们可以在结构中,但不是必需的)以在读取数据时接收数据,其中sscanf()
进行解析和拆分。然后,您可以验证状态码是否正确,时间是否合理等等。然后,您将累积信息添加到“统计结构”中,该结构与您当前拥有的struct climate_info
有关,但与之不同。例如,它不需要Geohash列或压力列,但是需要确定最低温度和时间,以及确定最高温度和时间。您可以累计积雪数量,雷击数量,湿度和云量以及当前温度。然后,当您完成文件时,可以平均温度,湿度和云量值,并可以打印聚合。
由于您明智地使用fgets()
从文件中读取行(请勿更改!),因此应使用sscanf()
来解析行。您需要:
char state[3];
)long long millitime;
)double humidity;
)double snow;
,因为格式为浮点数),double cloud;
),double lightning
)double temperature;
)。然后您使用
阅读它们if (sscanf(line, "%2[A-Z] %lld %*s %lf %lf %lf %lf %*lf %lf",
state, &millitime, &humidity, &snow, &cloud, &lightning, &temperature) == 7)
{
…validate data and report errors if appropriate…
…stash values appropriately; increment the count…
}
else
{
…report format error?…
}
请注意,格式中的*
会禁止分配;该列已读取但被忽略。代码检查压力是否为数字列。除了“必须存在”之外,它不会验证geohash列。可以将大小指定为上限%*12s
。
使用fgets()
和sscanf()
的众多优点之一是,您可以更加清楚地报告错误-您可以说“ XXX行中的状态代码不正确”,然后打印该行因为您仍然可以使用它。使用fscanf()
,您将无法如此轻松地就行内容进行报告,这使得调试数据的人变得更加困难。