0

I'm trying to read data from an stl file, one character at a time using scanf/fscanf. I call scanf many times in my program, but input all the data at the first instance. It works perfectly for a while, but it seems like as soon as scanf is called the 1022nd or 1023rd time, the program stops and prompts for more input, even though there is plenty left to scan.

I've written a program before that called scanf more than 40,000 times on one input, so I don't know what the deal is...

It seems to stop working at the first scanf in getnormal() when z == 7;

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

void getnormal(char[], double[]);
void getvertices(char[], double[], int);

int main (int argc, char *argv[]) {
    unsigned char trash = 0;
    int z = 0;

    char num[20];
    for (int i = 0; i < 20; i++)
        num[i] = 48;

    double normal [3] = {0,0,0};
    double vertices [9] = {0,0,0,0,0,0,0,0,0};

    //FILE *in = fopen(argv[1], "r");
    //FILE *out = fopen(argv[2], "w");

    while (trash != '\n')
        scanf("%c", &trash);

    while (1) {
        getnormal(num, normal);
        for (int i = 1; i <= 3; i++)
            getvertices(num, vertices, i);
        z++;
    }
}

double getnumber(char num[]) {
    unsigned char trash = 0;

    for (int i = 0; i < 20; i++)
        num[i] = 48;

    scanf("%c", &trash);

    for (int j = 0; trash != ' ' && trash != '\n'; j++) {
        num[j] = trash;
        scanf("%c", &trash);

        if (trash == 'e') {
            for (int h = 0; h < 4; h++)
                scanf("%c", &trash);
            break;
        }
    }
    return atof(num);
}

void getnormal(char num[], double normal[]) {
    unsigned char trash = 0;

    while (trash != 'm')
        scanf("%c", &trash);
    while (trash != 'l')
        scanf("%c", &trash);

    scanf("%c", &trash);

    for (int i = 0; i < 3; i++)
        normal[i] = getnumber(num);

    printf("\nnormal:");
    for (int i = 0; i < 3; i++)
        printf(" %f", normal[i]);
    printf("\n");
}

void getvertices(char num[], double vertices[], int vertex) {
    unsigned char trash = 0;

    vertex = (vertex-1) * 3;

    while (trash != 'x')
        scanf("%c", &trash);
    scanf("%c", &trash);

    for (int i = 0; i < 3; i++)
        vertices[vertex+i] = getnumber(num);

    printf("vertex:");
    for (int i = 0; i < 3; i++) {
        printf(" %f", vertices[vertex+i]);
    }
    printf("\n");
}

Here's the input:

solid Untitled-56807ca1
facet normal 0.0 0.0 -1.0
outer loop
vertex 100.0 50.0 0.0
vertex 0.0 0.0 0.0
vertex 0.0 50.0 0.0
endloop
endfacet
facet normal 0.0 0.0 -1.0
outer loop
vertex 0.0 0.0 0.0
vertex 100.0 50.0 0.0
vertex 100.0 0.0 0.0
endloop
endfacet
facet normal -1.0 0.0 0.0
outer loop
vertex 0.0 50.0 67.80499999999999
vertex 0.0 0.0 0.0
vertex 0.0 0.0 67.80499999999999
endloop
endfacet
facet normal -1.0 0.0 0.0
outer loop
vertex 0.0 0.0 0.0
vertex 0.0 50.0 67.80499999999999
vertex 0.0 50.0 0.0
endloop
endfacet
facet normal -0.0 1.0 0.0
outer loop
vertex 0.0 50.0 67.80499999999999
vertex 100.0 50.0 0.0
vertex 0.0 50.0 0.0
endloop
endfacet
facet normal -0.0 1.0 0.0
outer loop
vertex 100.0 50.0 0.0
vertex 0.0 50.0 67.80499999999999
vertex 100.0 50.0 67.80499999999999
endloop
endfacet
facet normal 1.0 0.0 0.0
outer loop
vertex 100.0 50.0 0.0
vertex 100.0 0.0 67.80499999999999
vertex 100.0 0.0 0.0
endloop
endfacet
facet normal 1.0 0.0 0.0
outer loop
vertex 100.0 0.0 67.80499999999999
vertex 100.0 50.0 0.0
vertex 100.0 50.0 67.80499999999999
endloop
endfacet
facet normal -0.0 -1.0 -0.0
outer loop
vertex 100.0 0.0 67.80499999999999
vertex 0.0 0.0 0.0
vertex 100.0 0.0 0.0
endloop
endfacet
facet normal -0.0 -1.0 -0.0
outer loop
vertex 0.0 0.0 0.0
vertex 100.0 0.0 67.80499999999999
vertex 0.0 0.0 67.80499999999999
endloop
endfacet
facet normal 0.8393626319551987 8.038371845750061e-18 0.5435718646851044
outer loop
vertex 100.0 50.0 67.80499999999999
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 100.0 0.0 67.80499999999999
endloop
endfacet
facet normal 0.8393626319551987 8.038371845750061e-18 0.5435718646851044
outer loop
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 100.0 50.0 67.80499999999999
vertex 68.99999999999989 34.49999999999993 115.67399999999996
endloop
endfacet
facet normal -0.8393626319552003 -1.4889432537737797e-17 0.5435718646851019
outer loop
vertex 30.9999999999999 15.49999999999995 115.67399999999996
vertex 0.0 50.0 67.80499999999999
vertex 0.0 0.0 67.80499999999999
endloop
endfacet
facet normal -0.8393626319552003 -1.4889432537737797e-17 0.5435718646851019
outer loop
vertex 0.0 50.0 67.80499999999999
vertex 30.9999999999999 15.49999999999995 115.67399999999996
vertex 30.9999999999999 34.49999999999993 115.67399999999996
endloop
endfacet
facet normal -5.5971483140148576e-18 -0.9513689920122365 0.30805363337837904
outer loop
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 0.0 0.0 67.80499999999999
vertex 100.0 0.0 67.80499999999999
endloop
endfacet
facet normal -5.5971483140148576e-18 -0.9513689920122365 0.30805363337837904
outer loop
vertex 0.0 0.0 67.80499999999999
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 30.9999999999999 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal 9.646494768713815e-18 0.9513689920122359 0.30805363337838126
outer loop
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 100.0 50.0 67.80499999999999
vertex 0.0 50.0 67.80499999999999
endloop
endfacet
facet normal 9.646494768713815e-18 0.9513689920122359 0.30805363337838126
outer loop
vertex 100.0 50.0 67.80499999999999
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 68.99999999999989 34.49999999999993 115.67399999999996
endloop
endfacet
facet normal 0.0 -0.8819736246769688 0.47129876445219904
outer loop
vertex 49.99999999999989 24.99999999999994 133.45199999999997
vertex 30.9999999999999 15.49999999999995 115.67399999999996
vertex 68.99999999999989 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal 0.6832351395351168 5.963605871623595e-18 0.7301984278978073
outer loop
vertex 68.99999999999989 34.49999999999993 115.67399999999996
vertex 49.99999999999989 24.99999999999994 133.45199999999997
vertex 68.99999999999989 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal -0.6832351395351168 5.963605871623845e-18 0.7301984278978073
outer loop
vertex 49.99999999999989 24.99999999999994 133.45199999999997
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 30.9999999999999 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal -0.0 -0.0 1.0
outer loop
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 30.9999999999999 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal -0.0 -0.0 1.0
outer loop
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 68.99999999999989 34.49999999999993 115.67399999999996
endloop
endfacet
facet normal -0.0 0.8819736246769686 0.47129876445219915
outer loop
vertex 49.99999999999989 24.99999999999994 133.45199999999997
vertex 68.99999999999989 34.49999999999993 115.67399999999996
vertex 30.9999999999999 34.49999999999993 115.67399999999996
endloop
endfacet
endsolid Untitled-56807ca1

Here's the output:

normal: 0.000000 0.000000 -1.000000
vertex: 100.000000 50.000000 0.000000
vertex: 0.000000 0.000000 0.000000
vertex: 0.000000 50.000000 0.000000

normal: 0.000000 0.000000 -1.000000
vertex: 0.000000 0.000000 0.000000
vertex: 100.000000 50.000000 0.000000
vertex: 100.000000 0.000000 0.000000

normal: -1.000000 0.000000 0.000000
vertex: 0.000000 50.000000 67.805000
vertex: 0.000000 0.000000 0.000000
vertex: 0.000000 0.000000 67.805000

normal: -1.000000 0.000000 0.000000
vertex: 0.000000 0.000000 0.000000
vertex: 0.000000 50.000000 67.805000
vertex: 0.000000 50.000000 0.000000

normal: -0.000000 1.000000 0.000000
vertex: 0.000000 50.000000 67.805000
vertex: 100.000000 50.000000 0.000000
vertex: 0.000000 50.000000 0.000000

normal: -0.000000 1.000000 0.000000
vertex: 100.000000 50.000000 0.000000
vertex: 0.000000 50.000000 67.805000
vertex: 100.000000 50.000000 67.805000

normal: 1.000000 0.000000 0.000000
vertex: 100.000000 50.000000 0.000000
vertex: 100.000000 0.000000 67.805000
vertex: 100.000000 0.000000 0.000000
chqrlie
  • 131,814
  • 10
  • 121
  • 189
James E.
  • 1
  • 2
  • 2
    How do you get out of the `while(1)` loop? – Thomas Matthews Dec 30 '15 at 04:31
  • Have you considered using `fread` instead of `fscanf`? – Thomas Matthews Dec 30 '15 at 04:32
  • When you used the debugger, which statement is causing the issue? – Thomas Matthews Dec 30 '15 at 04:33
  • nothing is written to break the while(1); but that means the entirety of my input should have been scanned. I haven't heard of fread; I'll look it up, but I'm wondering why scanf is acting this way. I'm using xcode on the mac, and I'm not sure exactly what you mean by the debugger. I don't think there's any error in my code, but rather that there are intricacies to scanf that I'm not familliar with. – James E. Dec 30 '15 at 04:38
  • Please post the input to the program. – R Sahu Dec 30 '15 at 05:00
  • Here you go, posted. – James E. Dec 30 '15 at 05:31
  • That looks like a very eccentric way of reading the data. I think you should be using `fgets()` to read lines, and then using `sscanf()` to analyze them. You should be checking the value returned by `scanf()` more frequently than you are. – Jonathan Leffler Dec 30 '15 at 05:46
  • I don't see any checks to detect EOF. What logic are you using to terminate the program? – R Sahu Dec 30 '15 at 06:00
  • Is it any wonder that your program is malfunctioning, when you neglect the return value of `scanf` that tells you whether or not it was successful, and just go on to use `trash` (possibly an uninitialised variable) as though `scanf` worked every time? – autistic Dec 30 '15 at 06:16
  • 1
    @JamesE., think carefully about Johathan's comment. The reason there is a general favor for reading a line-at-a-time and then parsing the line for the individual data is that it removes the sensitivity of the *format-string* from the read operation. There are times when you have a guaranteed identical line format where reading with the `scanf` family of functions makes sense. Here you are way outside that ideal. – David C. Rankin Dec 30 '15 at 06:46
  • lol @ trash variable – M.M Dec 30 '15 at 07:18
  • Why are you not using the `%f` format specifier in `fscanf`? – Thomas Matthews Dec 30 '15 at 07:22

2 Answers2

3

When you get into handling text files containing more than the basic "each line holds the same information", you are better served utilizing line-oriented input functions like fgets or getline in order to separate 'reading' of your data and 'processing (or parsing)' of your data that too often people attempt to shoehorn into a scanf format string that results in more grief than good.

As mentioned in my comment, when all the input lines are guaranteed to hold the same type and number of variables, and in the exact same format on every line, then the scanf family of input functions can be used fairly reliably. But when your data varies line-by-line, reading each line into a buffer and then having the luxury of writing a handler to parse and validate what was read will result in a far more robust code.

Before beginning your reading, you must decide on how you will hold your values in memory. Whether in a struct, an array, a combination? While C is flexible enough to allow you wide latitude in how you store your data, a bit of thinking up-front on what parts of your data are relatively fixed and what parts will continue to grow, can help you sort out a reasonable storage scheme.

In your case, the data you need that is relatively fixed in size is the name (or label) for your solid (e.g. Untitled-56807ca1 in your sample data). The number of normal/vertex sets can be a single number, and keeping track of the max number you can store is also a single number.

The data that will grow as you read from your input file will be the values for the facet normal arrays and the vertex arrays. Here you will need some way of reading as many as are contained in the file (likely without knowing how many are there when you start). Of course, if you do not need to store the data, but simply use the values as they are read, this isn't a concern, but in most cases, you want to be able to store your data so it can be passed to other parts of your code where it can be used.

While you can do it a number of ways, a nested struct, where the fixed values are members of the outer, or base, struct, which also holds a pointer to your data (or nested struct of normal and vertex arrays makes sense. You can make life easier with a simple create or initialization function that allocates and initializes the structs and their values each time a new named solid is read.

After setting up how you will hold/store your data, it is then just a matter of reading each line, examining/parsing the line contents, and taking the appropriate actions based on what you find in each line. You should also make sure you get what you expect to find in each line, and warn or throw an error if your code reads a line it doesn't understand.

There is no better way to put these pieces together than in a short example to read your posted input file so you can get a flavor for it. Note: there are many ways to do this in C, all with their advantages/disadvantages, this is just one for you to consider and to ask questions about to help your understand how a line-oriented approach may benefit what you are attempting to do. Look over the example and let me know what questions you have:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>  /* for ERANGE and errno     */
#include <math.h>   /* for HUGE_VALF, HUGE_VALL */

/* constants - num dimensions, initial facets
 * allocated within each solid, and the max
 * chars per-line for fgets to read
 */
enum { NDIM = 3, FACETS = 32, MAXC = 256 };

/* facets struct - declared as pointer member of 
 * struct solid allowing additional allocation to
 * hold as many normal/vertexes as required.
 */
typedef struct {
    double normal[NDIM];
    double vertex[NDIM][NDIM];
} facet;

/* struct solid holds the solid's name, 
 * a pointer to an array of stuct facet, 
 * the number of facets containing data, and 
 * the maximum presently allocated.
 */ 
typedef struct {
    char *name;
    facet *facet;
    size_t nfacets;
    size_t maxfacets;
} solid;

/* function prototypes */
solid *create_solid ();
solid *read_solid (solid **sol, FILE *fp);
void print_solid (solid *sol);
void free_solid (solid *sol);
double xstrtod (char *str, char **ep);

int main (int argc, char **argv) {

    solid *sol = NULL;  /* pointer to hold values */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open */
        fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
        return 1;
    }

    if (read_solid (&sol, fp)) {    /* read data from file  */
        print_solid (sol);          /* print data read      */
        free_solid (sol);           /* free all memory      */
    }
    if (fp != stdin) fclose (fp);   /* close if not stdin   */

    return 0;
}

/* read_solid takes the poiner address for a struct solid,
 * and will read all normal and vertexes into the struct,
 * updating 'nfacets' with the number of facets for which
 * there is data, and will validate each read and conversion
 * of values from string to double. retuns filled struct on
 * success, NULL otherwise
 */
solid *read_solid (solid **sol, FILE *fp)
{
    char line[MAXC] = {0};      /* temporary line buffer */
    size_t idx = 0, vidx = 0;   /* line & vertex indexes */

    if (!*sol) *sol = create_solid(); /* allocate & initialize struct */

    while (fgets (line, MAXC, fp)) {  /* read each line in file */

        size_t len = 0;
        char *p, *ep;
        p = ep = line;

        len = strlen (line);    /* get length & remove '\n' */
        if (line[len - 1] == '\n') line[--len] = 0;

        if (!(ep = strchr (line, ' '))) /* test if space in line */
        {   /* if endfacet, update nfacets */
            if (strcmp ("endfacet", line) == 0)  {
                (*sol)->nfacets++;
                if ((*sol)->nfacets == (*sol)->maxfacets) {
                    /* reallocate (*sol)->facets here, 
                     * update (*sol)->maxfacets to new size
                     */
                    fprintf (stderr, "read_solid() warning: limit reached\n"
                                    "you must reallocate or increase FACETS\n");
                    break;
                }
            }
            goto processed;
        }

        if (strncmp ("solid", line, ep - p) == 0) 
        {   /* begins with 'solid', set 'name' */
            (*sol)->name = strdup (ep + 1);
            goto processed;
        }
        else if (strncmp ("facet", line, ep - p) == 0) 
        {   /* read facet normal values */
            size_t i;
            while (*ep && (*ep < '0' || *ep > '9')) ep++;
            if (!*ep) { 
                fprintf (stderr, "read_solid() error: facet normal no values.\n");
                return NULL;
            }
            p = ep;
            for (i = 0; i < NDIM; i++) { /* convert to double & validate */
                (*sol)->facet[(*sol)->nfacets].normal[i] = xstrtod (p, &ep);
                p = ep;
            }
            goto processed;
        }
        else if (strncmp ("vertex", line, ep - p) == 0) 
        {   /* read vertex values */
            size_t i;
            p = ep + 1;

            for (i = 0; i < NDIM; i++) { /* convert to double & validate */
                (*sol)->facet[(*sol)->nfacets].vertex[vidx][i] = xstrtod (p, &ep);
                p = ep;
            }
            vidx = vidx < 2 ? vidx + 1 : 0; /* update/reset vertex index */
            goto processed;
        }
        else if (strncmp ("outer", line, ep - p) == 0) {
            goto processed;
        }
        else if (strncmp ("endsolid", line, ep - p) == 0) {
            goto processed;
        }
        else { /* if any line not processed - warn of unrecognized line */
            fprintf (stderr, "read_solid() warning: invalid line at '%zu'\n", idx);
        }
    processed:
        idx++;  /* update line index */
    }

    if (!(*sol)->nfacets) { /* if no facet data, free mem, return NULL */
        fprintf (stderr, "read_solid() error: no data read.\n");
        free_solid (*sol);
        return NULL;
    }

    return *sol;
}

/* simple allocate/initialize function
 * return must be assigned to pointer
 */
solid *create_solid ()
{
    size_t i;

    solid *sol = calloc (1, sizeof *sol);
    sol->facet = calloc (FACETS, sizeof *(sol->facet));
    sol->nfacets = 0;
    sol->maxfacets = FACETS;

    for (i = 0; i < FACETS; i++) {
        memset ((sol->facet)[i].normal, 0, NDIM * sizeof (double));
        memset ((sol->facet)[i].vertex, 0, NDIM * NDIM * sizeof (double));
    }

    return sol;
}

/* simple print of normals & vertexes to stdout */
void print_solid (solid *sol)
{
    if (!sol) {
        fprintf (stderr, "print_solid() error: invalid parameter 'sol'.\n");
        return;
    }

    size_t n, i;

    printf ("\nnormal and vertexes for solid: %s\n", sol->name);
    for (n = 0; n < sol->nfacets; n++) {
        printf ("\n  normal[%3zu] : %10.4f  %10.4f  %10.4f\n", n,
                sol->facet[n].normal[0], 
                sol->facet[n].normal[1],
                sol->facet[n].normal[2]);
        for (i = 0; i < NDIM; i++)
            printf ("   vertex[%2zu] : %10.4f  %10.4f  %10.4f\n", i,
                    sol->facet[n].vertex[i][0], 
                    sol->facet[n].vertex[i][1],
                    sol->facet[n].vertex[i][2]);
    }
}

/* free allocated memory */
void free_solid (solid *sol)
{
    if (sol->name) free (sol->name);
    if (sol->facet) free (sol->facet);
    if (sol) free (sol);
}

/* string to double with error checking. */
double xstrtod (char *str, char **ep)
{
    errno = 0;

    double val = strtod (str, ep);

    /* Check for various possible errors */
    if ((errno == ERANGE && (val == HUGE_VAL || val == HUGE_VALL)) ||
        (errno != 0 && val == 0)) {
        perror ("strtod");
        exit (EXIT_FAILURE);
    }

    if (ep && *ep == str) {
        fprintf (stderr, "No digits were found\n");
        exit (EXIT_FAILURE);
    }

    return val;
}

Compile (gcc)

gcc -Wall -Wextra -O3 -o bin/readsolid readsolid.c

Use/Output

$ ./bin/readsolid dat/solid.txt

normal and vertexes for solid: Untitled-56807ca1

  normal[  0] :     0.0000      0.0000     -1.0000
   vertex[ 0] :   100.0000     50.0000      0.0000
   vertex[ 1] :     0.0000      0.0000      0.0000
   vertex[ 2] :     0.0000     50.0000      0.0000

  normal[  1] :     0.0000      0.0000     -1.0000
   vertex[ 0] :     0.0000      0.0000      0.0000
   vertex[ 1] :   100.0000     50.0000      0.0000
   vertex[ 2] :   100.0000      0.0000      0.0000

  normal[  2] :     1.0000      0.0000      0.0000
   vertex[ 0] :     0.0000     50.0000     67.8050
   vertex[ 1] :     0.0000      0.0000      0.0000
   vertex[ 2] :     0.0000      0.0000     67.8050

  normal[  3] :     1.0000      0.0000      0.0000
   vertex[ 0] :     0.0000      0.0000      0.0000
   vertex[ 1] :     0.0000     50.0000     67.8050
   vertex[ 2] :     0.0000     50.0000      0.0000

  normal[  4] :     0.0000      1.0000      0.0000
   vertex[ 0] :     0.0000     50.0000     67.8050
   vertex[ 1] :   100.0000     50.0000      0.0000
   vertex[ 2] :     0.0000     50.0000      0.0000
<snip>

  normal[ 21] :     0.0000     -0.0000      1.0000
   vertex[ 0] :    69.0000     15.5000    115.6740
   vertex[ 1] :    31.0000     34.5000    115.6740
   vertex[ 2] :    31.0000     15.5000    115.6740

  normal[ 22] :     0.0000     -0.0000      1.0000
   vertex[ 0] :    31.0000     34.5000    115.6740
   vertex[ 1] :    69.0000     15.5000    115.6740
   vertex[ 2] :    69.0000     34.5000    115.6740

  normal[ 23] :     0.0000      0.8820      0.4713
   vertex[ 0] :    50.0000     25.0000    133.4520
   vertex[ 1] :    69.0000     34.5000    115.6740
   vertex[ 2] :    31.0000     34.5000    115.6740

Memory/Error Check

In any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserves a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory and to confirm that you have freed all the memory you have allocated.

For Linux valgrind is the normal choice. There are so many subtle ways to misuse a block of memory that can cause real problems, there is no excuse not to do it. There are similar memory checkers for every platform. They are all simple to use. Just run your program through it.

$ valgrind ./bin/readsolid dat/solid.txt
==4651== Memcheck, a memory error detector
==4651== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==4651== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==4651== Command: ./bin/readsolid dat/solid.txt
==4651==

normal and vertexes for solid: Untitled-56807ca1

  normal[  0] :     0.0000      0.0000     -1.0000
   vertex[ 0] :   100.0000     50.0000      0.0000
   vertex[ 1] :     0.0000      0.0000      0.0000
   vertex[ 2] :     0.0000     50.0000      0.0000
<snip>
==4651==
==4651== HEAP SUMMARY:
==4651==     in use at exit: 0 bytes in 0 blocks
==4651==   total heap usage: 4 allocs, 4 frees, 3,690 bytes allocated
==4651==
==4651== All heap blocks were freed -- no leaks are possible
==4651==
==4651== For counts of detected and suppressed errors, rerun with: -v
==4651== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

Note: this example ended up longer than I originally envisioned, but to provide adequate validation for any relatively sophisticated set of data, it will take a little bit of code to get it done correctly. Good luck.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
1

Your function getnumber has several problems:

The buffer num is initialized to all '0' without a null terminator. You patch some bytes into it until you see a space or a linefeed and call atof.

  • There is no test to prevent buffer overflow, invalid input may well cause that at some point in the input file.

  • The buffer is not null terminated. atof will stop on the first character that does not match the floating point syntax, but if all positions are digits, it will keep reading past the end of the num array.

The whole code is very cumbersome and the semantics are unclear.

You never test the return value from scanf: upon end of file, the contents of the unsigned char whose address is passed as argument to scanf will be indeterminate, most likely untouched from the previous value... potentially causing buffer overflow in getnumber as well.

There is no way for your program to break from the while (1) loop. Sooner or later, you will reach the end of file and your code will either invoke undefined behavior or get stuck in an infinite loop.

Rewrite your code with getchar() or fgets and properly check for end of file.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Thanks for your answer. It was really helpful. I'm pretty new to reading and parsing files, and fscanf was really the only function I was aware of or knew how to use. Now that I know about fgets and sscanf, I'll rewrite the code entirely using them instead. – James E. Dec 30 '15 at 08:03
  • @JamesE. Can you please click the grey check mark below the answer score to mark it as accepted? – chqrlie Jan 17 '16 at 22:21