Проверка нулевых / пустых значений с плавающей запятой при использовании sscanf - PullRequest
3 голосов
/ 09 апреля 2020

Следующая программа пытается прочитать входной файл построчно, используя fgets, и сохранить каждое значение с плавающей запятой comma delimited в массив структур, используя sscanf (этот аспект кода работает нормально). Проблема заключается в том, что программа должна также определить, когда значение с плавающей точкой отсутствует / пусто, и присвоить ему значение с плавающей точкой 1.500, которое затем сохраняется в массиве структур.

РЕДАКТИРОВАТЬ: Предполагается, что это будет скомпилировано с использованием VS2017, поэтому Windows.

* Примечание: Обратите внимание, что перед публикацией этого вопроса были изучены следующие вопросы:

Как проверить, является ли строка, возвращаемая scanf, нулевой

Как заставить scanf продолжить работу с пустым набором сканирования

Пример входной файл (пропущенное значение во втором ряду):

0.123f, 0.234f, 0.345f, 0.456f, 0.567f
1.987f, , 7.376f, 2.356f, 5.122f
9.111f, 1.234f, 7.091f, 6.672f, 9.887f

Требуемый вывод ( пропущенное значение во втором ряду обнаружено и установлено на 1.500 ):

0.123 0.234 0.345 0.456 0.567
1.987 1.500 7.376 2.356 5.122
9.111 1.234 7.091 6.672 9.887

До сих пор при первой попытке была предпринята попытка отсканировать все 5 чисел с плавающей запятой (каждый с суффиксом 'f') в строки, а затем проверить, являются ли эти строки нулевыми / пустыми или нулевой длины, используя strcmp и strlen соответственно, и, наконец, попытался использовать sscanf снова на каждом из этих va можно читать каждый в массив структур.

2-я попытка включала проверку, чтобы проверить, был ли sscanf успешным с использованием if (sscanf(line, "%ff", &data[i].x) == NULL) { // ...some alert and assign 1.500}, который тоже не работал. 3-я попытка, как показано ниже:

#include "stdio.h"

int main() {

typedef struct {
    float x, y, vx, vy, mass;
}DATA;

    FILE *file = fopen("null_detector.txt", "r");
    if (file == NULL)
    {
        printf(stderr, "ERROR: file not opened.\n");
        return EXIT_FAILURE;
    }
    int N= 3;
    DATA* data = malloc(Nbodies * sizeof * data); // Array allocation
    char line[256];
    int i;
    int inc = 1;
    for (i = 0; i < Nbodies; i += inc)
    {
        fgets(line, sizeof(line), file);

        // **Some info:
        // Scan 5 float variables per line (this part works fine)
        sscanf(line, "%ff, %ff, %ff, %ff, %ff",
            &data[i].x, &data[i].y, &data[i].vx, &data[i].vy, &data[i].mass); // %ff accounts for 'f' suffix

        // Now check if any of above vars are empty/NULL.
        // NOTE: aware that these vars CANNOT be compared to NULL,
        // but has been included to try and provide clarity for end goal
        if (data[i].x == NULL)
        {
            //.. assign 1.500 to data[i].x
        }
        if (data[i].y == NULL)
        {
            //... same as above etc
        }
        // ...Repeat IF statements for all 5 vars

    }

     //Print the contents of array of structs to check for correct output
    for (i = 0; i < Nbodies; i++)
    {
        printf("%.3f %.3f %.3f %.3f %.3f\n", data[i].x, data[i].y, data[i].vx, data[i].vy, data[i].mass);
    }

    return 0;
}

Резюме:

Кто-нибудь знает, как эту программу можно изменить на:

  • обнаруживать пропущенные значения с плавающей точкой в ​​каждой строке файла после чтения их с помощью fgets
  • заменить отсутствующие значения с плавающей запятой на значение с плавающей запятой 1.500
  • записать эти значения в массив структур, как успешно работают не пропущенные значения?
  • Как отмечено в коде, я знаю, что переменные с плавающей точкой struct нельзя сравнивать с NULL. Я включил это сравнение в код, чтобы попытаться внести некоторую ясность в отношении конечной цели.

Ответы [ 2 ]

1 голос
/ 09 апреля 2020

Этого также можно добиться только с sscanf, если между запятыми есть хотя бы пробел, когда отсутствует входное значение.

#include <stdio.h>
int main(void) {
  char *str[] = {"0.123f, 0.234f, 0.345f, 0.456f, 0.567f",
                 "1.987f, , 7.376f, 2.356f, 5.122f",
                 "9.111f, 1.234f, 7.091f, 6.672f, 9.887f"};

  float float_arr[3][5];
  char temp[5][7];

  for (unsigned i = 0; i < 3; i++) {
    if (5 != sscanf(str[i], "%6[^,],%6[^,],%6[^,],%6[^,],%6[^,]", 
                    temp[0], temp[1], temp[2], temp[3], temp[4]))
      return printf("Error\n"), 1;

    for (unsigned j = 0; j < 5; j++)
      if (1 != sscanf(temp[j], "%ff", &float_arr[i][j]))
        float_arr[i][j] = 1.500f;
  }

  // printing the result
  for (unsigned i = 0; i < 3; i++) {
    for (unsigned j = 0; j < 5; j++)
      printf("%ff ", float_arr[i][j]);
    printf("\n");
  }
  return 0;
}

Выход

0.123000f 0.234000f 0.345000f 0.456000f 0.567000f 
1.987000f 1.500000f 7.376000f 2.356000f 5.122000f 
9.111000f 1.234000f 7.091000f 6.672000f 9.887000f 
1 голос
/ 09 апреля 2020

Вы можете использовать strsep для разделения каждой строки.

str = strsep(&line, ",")

Использование одной функции для установки значения данных:

void set_data(DATA *dt, int count, float f) {
    switch(count) {
        case 0: dt->x = f; break;
        case 1: dt->y = f; break;
        case 2: dt->vx = f; break;
        case 3: dt->vy = f; break;
        case 4: dt->mass = f; break;
    }
}

Полный код:


#include <stdio.h>  
#include <unistd.h>  
#include <string.h>  
#include <stdlib.h> 

typedef struct {
    float x, y, vx, vy, mass;
}DATA;

void set_data(DATA *dt, int count, float f) {
    switch(count) {
        case 0: dt->x = f; break;
        case 1: dt->y = f; break;
        case 2: dt->vx = f; break;
        case 3: dt->vy = f; break;
        case 4: dt->mass = f; break;
    }
}

int main() {

    FILE *file = fopen("text.txt", "r");
    if (file == NULL)
    {
        printf( "ERROR: file not opened.\n");
        return EXIT_FAILURE;
    }
    int N= 3;
    DATA* data = malloc(N * sizeof(data)); // Array allocation
    char *line;
    int i;
    int inc = 1;
    size_t n = 0;
    for (i = 0; i < N; i += inc)
    {
        getline(&line, &n, file);
        int count = 0;
        char *str;
        while((str = strsep(&line, ",")) != NULL) {
            if (strcmp(str, " ") == 0) {
                set_data(&data[i], count, 1.5);
            } else {
                set_data(&data[i], count, atof(str));
            }
           // printf("count = %d\n", count);
            // printf("token: %s\n", str);
            count++;
        }

    }

     //Print the contents of array of structs to check for correct output
    for (i = 0; i < N; i++)
    {
        printf("%.3f %.3f %.3f %.3f %.3f\n", data[i].x, data[i].y, data[i].vx, data[i].vy, data[i].mass);
    }

    return 0;
}

Вход:

#cat text.txt
0.123f, 0.234f, 0.345f, 0.456f, 0.567f
1.987f, , 7.376f, 2.356f, 5.122f
9.111f, 1.234f, 7.091f, 6.672f, 9.887

Выход:

0.123 0.234 0.345 0.456 0.567
1.987 1.500 7.376 2.356 5.122
9.111 1.234 7.091 6.672 9.887
...