Somewhat unexperienced with C here!

I'm using CLion to write a program and keep getting this warning message whenever I use fscanf to store a value from an input file into a variable:

Clang-Tidy: 'fscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead

I don't understand this error as I thought fscanf was the function I should be using to read input files? Can someone explain (at a noob level) what's wrong with the way I'm using it?

Here's a sample of my code:

FILE *initial_configuration_box_1_pointer;
initial_configuration_box_1_pointer = fopen("initial_configuration_box_1.xyz", "r");
fscanf(initial_configuration_box_1_pointer, "%d\n", &N1); // Warning here.
fscanf(initial_configuration_box_1_pointer, "pid\tx\ty\tz\n"); // No warning here.
for (i = 1; i <= n1; i++)
{
    fscanf(initial_configuration_box_1_pointer, "p\t%lf\t%lf\t%lf\n", &rx1[i - 1], &ry1[i - 1], &rz1[i - 1]); // Warning here.
}
fclose(initial_configuration_box_1_pointer);

I'm aware similar questions have been asked, but I couldn't understand any of the (few) answers they got...

1

There are 1 best solutions below

0
On

There are a lot of good reasons for a beginner to avoid scanf completely. (Read http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html). If you're going to use it interactively, never end a format string with whitespace, since doing so will just confuse the user. And always check the value returned by scanf to see if it actually matched any input. A common error is for the input to fail to match the expected data, and the scanf loop becomes an infinite loop repeatedly checking the same invalid input. Perhaps the warning is suggesting the second point above: since scanf does not validate the input for you, you have to do it explicitly by checking how many conversion specifiers scanf was able to match. Try something like:

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

int
main(int argc, char ** argv)
{
        int n1;
        const char *path = argc > 1 ? argv[1] : "initial_configuration_box_1.xyz";
        FILE *ifp;
        if( (ifp = fopen(path, "r")) == NULL ){
                perror(path);
                return EXIT_FAILURE;
        } 
        if( 1 != fscanf(ifp, "%d", &n1) || n1 <= 0 ){
                fprintf(stderr, "Invalid input\n");
                return EXIT_FAILURE;
        }
        fscanf(ifp, " pid x y z");
        double rx1[n1];
        double ry1[n1];
        double rz1[n1];

        for( int i = 0; i < n1; i++ ){
                if( 3 != fscanf(ifp, " p %lf %lf %lf", rx1 + i, ry1 + i, rz1 + i) ){
                        fprintf(stderr, "Invalid input near line %d\n", i);
                        return EXIT_FAILURE;
                }               
        }
        if( fclose(ifp) ){
                perror(path);
                return EXIT_FAILURE;
        }
        return EXIT_SUCCESS;
}

Note that whitespace in a scanf format string does not match exactly, so using \n or \t or is all the same. Usually, people just use a single space to make it easier to read. Also, whitespace between certain conversion specifiers (notable %d and %lf) is irrelevant, and only included for readability.