0

For my assignment I was given a program to add error checks to, I was add the first two quickly (any comment with an X after it I believe I've solved) However I believe the problem for this error check in line 60 is that fscanf willingly reads in chars to something that takes integers, so I need to add something that prints out an error and stops the program if a char is attempted to be read in. I am also not sure what to error check for in create_graph and read_edge yet. The files to be read into this program are of a format like this:

4 5
1 2 0.2
2 3 0.3
3 4 -3.7
1 4 0.2
3 1 0.4

My most recent attempt has been:

   if (scanf("%d", &n) == 0 || scanf("%d", &m) == 0){
    printf("Error: Expected an Integer");

    return 0;
}

Current code:

to try and scan the input to make sure they're integers.

// missing error check (you may need to modify the function's return
// value and/or parameters)
edge read_edge(FILE* file) {
    edge e;
    fscanf(file, "%d %d %f", &e.source, &e.target, &e.weight);
    return e;
}

graph create_graph(int n, int m) {
    graph g = {
        .n = n,
        .m = m,
        .vertices = calloc(n, sizeof(vertex)),
        .edges = calloc(m, sizeof(edge)),
    };

    for(int i = 0; i < n; i++) {
        g.vertices[i] = i + 1;
    }

    return g;
}

int main(int argc, char* argv[]) {
    // missing error check -- related to argc/argv X
    if (argv[2] != '\0')
    {
        printf("Wrong number of arguments.\n");
        return 0;
    }
    // missing error check (errno) X
    FILE* file = fopen(argv[1], "r");

    if (file == NULL) {
        printf("Unable to open file: %s\n", strerror(errno));
        return 0;
    }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    int n, m;
    // missing error check
    fscanf(file, "%d %d", &n, &m);

    if (scanf("%d", &n) == 0 || scanf("%d", &m) == 0){
        printf("Error: Expected an Integer");

        return 0;
    }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
    graph g = create_graph(n, m);

    for (int i = 0; i < m; i++) {
        // missing error check (after you fix read_edge)
        g.edges[i] = read_edge(file);
    }

    printf("%d %d\n", g.n, g.m);

    return 0;
}

As it is now the program just crashes when trying to read in a file.

Til
  • 5,150
  • 13
  • 26
  • 34
DazerC
  • 37
  • 6
  • 2
    The reason you're using *both* `fscanf` *and* `scanf` to populate from file, discard, then populate from console, the same variables `n` and `m` is... ??? it's the `fscanf` that should be checked. The `scanf` shouldn't even be there. – WhozCraig Jul 12 '19 at 05:23
  • This is what I've been able to come up with with a bit of research, but I'm lost here. So if I replace the scanf's with fscanf's I just end up with compiler errors. What exactly IS happening here? I thought fscanf read the values in, integer or not. Then scanf scanned them and compared them to see if they were integers. – DazerC Jul 12 '19 at 05:31
  • 1
    OT: This check is wrong: `if (argv[2] != '\0')` That is not the way to check for `argv[1]` being present. Use `if (argc < 2)` – Support Ukraine Jul 12 '19 at 05:35
  • 2
    For this `fscanf(file, "%d %d", &n, &m);` you need to do `if (fscanf(file, "%d %d", &n, &m) != 2) { // add error handling code };` – Support Ukraine Jul 12 '19 at 05:36
  • OT: Strongly recommend `fgets` instead of `fscanf` but I guess you didn't write that part but that it's part of the code give to you. – Support Ukraine Jul 12 '19 at 05:37
  • 1
    This code `.vertices = calloc(n, sizeof(vertex)),` is missing a check for NULL – Support Ukraine Jul 12 '19 at 05:38
  • I have heard that forms of scanf are not the way to go for this sort of thing, but its what I somewhat knew how to use, how would I go about this a better way with fgets? – DazerC Jul 12 '19 at 05:40
  • 1
    The comment of @4386427 in mind: `read_edge()` may fail if either end of file is reached or something is wrong with file. I would think about what `read_edge()` should return in this case to remark that no edge could been read. May be, an `edge` which contains invalid values. Of course, this has to be checked after calling `read_edge()` and before doing anything else with the returned `edge` value. – Scheff's Cat Jul 12 '19 at 06:20
  • @DazerC Use `fgets` to read a whole line from the file into a string. Then use `sscanf` to scan the string for numbers. This will make error handling a lot easier. See https://stackoverflow.com/questions/22330969/using-fscanf-vs-fgets-and-sscanf – Support Ukraine Jul 12 '19 at 06:39
  • Thank you all for your input! I'm going to continue on this tomorrow with these thoughts in mind. It should help me figure out the error check for the last bit you pointed out! – DazerC Jul 12 '19 at 07:13
  • regarding: `if (scanf("%d", &n) == 0 || scanf("%d", &m) == 0)` The call to `scanf()` can return 1 (the only desirable returned value) or 0 (if the single input format conversion specifier fails) or EOF. In general, 0 and EOF are not tested for as (in this case) 1 is the only return value of interest. – user3629249 Jul 13 '19 at 13:42
  • OT: regarding: `printf("Error: Expected an Integer");` Error messages should be output to `stderr`, not `stdout` Suggest: `fprintf( stderr, "scanf to input an integer failed\n" );` – user3629249 Jul 13 '19 at 13:45
  • after outputting an error message, this statement: `return 0;` is not a good idea. In general, returning 0 indicates success Suggest: `exit( EXIT_FAILURE );` Where both `exit()` and `EXIT_FAILURE` are exposed via the header file: `stdlib.h` – user3629249 Jul 13 '19 at 13:48

1 Answers1

1

How to error check:

fscanf(file, "%d %d", &n, &m);

Suggest:

if( fscanf(file, "%d %d", &n, &m) != 2 )
{
    fprintf( "fscanf of first line from the input file failed\n );
    exit( EXIT_FAILURE );
}

// implied else, fscanf successful

Note: the scanf() family of functions returns the number of successful input format conversions (or EOF)

regarding:

if (argv[2] != '\0')
{
    printf("Wrong number of arguments.\n");
    return 0;
}

When discussing a command line parameter problem, it is best to display (on stderr) a USAGE statement, similar to:

if( argc != 2 )
{
    fprintf( stderr, "USAGE: %s <inputFileName>\n", argv[0] );
    exit( EXIT_FAILURE );
}

// implied else, correct number of command line parameters

Note: argv[0] is always the name of the executable

user3629249
  • 16,402
  • 1
  • 16
  • 17