Как динамически присваивать значения структуре - PullRequest
0 голосов
/ 23 ноября 2018

Я озадачен тем, как получить доступ и изменить значения структуры.Программа принимает некоторые внешние файлы и маркирует каждую строку и классифицирует их в следующих полях климатической информации.Внешние файлы выглядят примерно так:

Формат 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).эпоха), третий столбец - строка геохэш для местоположения (не используется), четвертый - процентная влажность, пятый - наличие снега (значения 0,0 или 1,0), шестой - процент облачного покрова, седьмой - количество ударов молнии,восьмое - давление (единицы измерения неизвестны, но данные не используются, поэтому это не имеет значения), а девятое - температура поверхности (измеряется в Кельвинах).Я понимаю, что должен преобразовать временную метку и температуру поверхности, поэтому меня это не беспокоит.Мне нужно агрегировать данные по полному состоянию (независимо от геохеша), отслеживать минимальные и максимальные температуры и время, когда они произошли, и подсчитывать количество записей для состояния, чтобы значения можно было усреднить.

Вывод для одного состояния должен выглядеть следующим образом:

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

1 Ответ

0 голосов
/ 23 ноября 2018

Значения, считанные из файла, не должны присваиваться непосредственно элементам структуры.Вам нужен один набор переменных (они могут быть в структуре, но это необязательно), чтобы получать данные в том виде, как они читаются, с sscanf(), выполняющим анализ и разбиение.Затем вы проверяете, что код состояния правильный, что время достоверно, и так далее.Затем вы добавляете совокупную информацию в «статистическую структуру», которая связана с struct climate_info, который у вас есть, но отличается от него.Например, ему не нужен столбец геохеша или столбец давления, но нужны минимальная температура и время, когда он был обнаружен, а также максимальная температура и время, когда он был обнаружен.Вы накапливаете количество снежного покрова, количество ударов молнии, влажность, облачность и текущую температуру.Затем, когда вы закончите файл, вы можете усреднить значения температуры, влажности и облачного покрова и распечатать агрегаты.

Поскольку вы разумно используете 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?… 
}

Обратите внимание, что * в форматах подавляет назначение;столбец читается, но игнорируется.Код проверяет, что давление представляет собой числовой столбец;он не проверяет столбец геохэш за пределами «он должен существовать».Можно было бы указать размер в качестве верхней границы %*12s.

Одним из многих преимуществ использования fgets() и sscanf() является то, что вы можете сообщать об ошибках гораздо более доходчиво - вы можете сказать: "код состояния был неверным в строке XXX: ", а затем выведите строку, поскольку она еще доступна.Используя fscanf(), вы не сможете так легко сообщать о содержимом строки, что затрудняет отладку данных.

...