0

Overview:

The following program attempts to scan 5 float values per line from an input file using sscanf into an array of structs. If a value(s) is missing from a line during sscanf, the program should detect this missing value and assign it the value 1.500, but this substitution step isn't working.

The input file looks like this (note how the third value in the second row is missing):

0.123f, 0.234f, 0.345f, 0.456f, 0.567f
1.123f, 1.642f, , 1.456f, 1.567f
1.678f, 1.789f, 1.891f,1.911f, 2.001f

Expected output (note how the third value in the second row has been substituted with 1.500):

0.123, 0.234, 0.345, 0.456, 0.567
1.123, 1.642, 1.500, 1.456, 1.567
1.678, 1.789, 1.891, 1.911, 2.001

Actual output (not working as expected):

0.123 0.234 0.345 0.456 0.567
1.123 1.642 -431602080.000 -431602080.000 -431602080.000
1.678 1.789 1.891 1.911 2.001 

Current attempt:

#include "stdio.h"

int main() {

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

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

        // Scan 5 float variables per line (this works fine)
        sscanf(line, "%ff, %ff, %ff, %ff, %ff", 
            &data[i].x, &data[i].y, &data[i].vx, &data[i].vy, &data[i].mass);

        // Check if any of the above scanned vars are NULL.
        // Used individual IF statements instead of IF/ELSE to cover
        // multiple NULL occurrences per line
        float substitute = 1.500;
        if (&data[i].x == '\0') { data[i].x = substitute; }
        if (&data[i].y == '\0') { data[i].y = substitute; }
        if (&data[i].vx == '\0') { data[i].vx = substitute; }
        if (&data[i].vy == '\0') { data[i].vy = substitute; }
        if (&data[i].mass == '\0') { data[i].mass = substitute; }
    }

    // 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;
}

Summary:

Can anyone see why this doesn't work? I thought that the individual IF statements after sscanf would successfully substitute the missing value for 1.500. It seems that this method can atleast detect when a value is missing, but cannot replace the missing value with 1.500.

p.luck
  • 646
  • 2
  • 9
  • 34
  • 2
    These can never be `NULL` as long as `data` allocated properly. . What you really want is to check the return value of `sscanf`. – Eugene Sh. Apr 08 '20 at 22:08
  • 1
    Eugene is right, but the comparison would probably still work, accidentally. Your problem is that not only the third, but also the fourth and fifth conversion fail because the second comma is not skipped by sscanf. You should sscanf single strings (words, or tokens) from line and sscanf *from these single strings* alternating numbers and commas. If a single number parsing fails you can assume that it is, in fact, a comma, and substitute it. – Peter - Reinstate Monica Apr 08 '20 at 22:14
  • Generally it is essential to use the return value of (s)scanf, which is the number of successful conversions. You will see that for the faulty line the return value is 2 (and not 5). Reading items from a string with sscanf is a bit tricky because the string cannot maintain a reading position the way a FILE does; reading always starts at the given pointer. You must increment the pointer by the number of characters "consumed so far" which can be obtained with the `%n` fake conversion specification. – Peter - Reinstate Monica Apr 08 '20 at 22:21

0 Answers0