繁体   English   中英

如何为结构动态分配值

[英]How to assign values dynamically to a struct

我对如何访问和更改结构的值感到困惑。 该程序接收一些外部文件,并对每个字符串进行标记,然后将其归类为以下气候信息字段。 外部文件如下所示:

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");

从文件中读取的值不应直接分配给结构的元素。 您需要一组变量(它们可以在结构中,但不是必需的)以在读取数据时接收数据,其中sscanf()进行解析和拆分。 然后,您可以验证状态码是否正确,时间是否合理等等。 然后,您将累积信息添加到“统计结构”中,该struct climate_info您当前拥有的struct climate_info相关但又不同。 例如,它不需要Geohash列或压力塔,但是需要确定最低温度和时间,以及确定最高温度和时间。 您可以累计积雪数量,雷击数量,湿度和云量以及当前温度。 然后,当您完成文件时,可以平均温度,湿度和云量值,并且可以打印聚合。

由于您明智地使用fgets()从文件中读取行(请勿更改!),因此应使用sscanf()来解析行。 你需要:

  • 状态码( char state[3]; ),
  • 时间值( long long millitime; ),
  • 湿度值( double humidity; ),
  • “ snow present”(雪当前)值( 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() ,您将无法如此轻松地报告行内容,这使得调试数据的人变得更加困难。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM