cstructc89ansi-c

Safest way to read a string and store as int in a struct


I am using ANSI C on the gcc compiler (with -ansi).

I need to read user input for the month, day, hour and minute into a struct and they:

Struct definition

typedef struct 
    {
      int month;
      int day;
      int hour;
      int minute;
    } date_time_t;

date_time_t departure_date[50];

Typechecking with String Conversion

I want to check the user input to stop the program crashing if they provide a "~" to the scanf("%i", departure_date->month);

So I am reading the value as a string first like this:

char temp_month[3]
char *ptr;
scanf("%s", temp_month)

And then typechecking the user input like this:

while input does not meet criteria -> ask for input that meets criteria

 while(strtol(temp_month,  &ptr, 36) <  1 ||
        strtol(temp_month,  &ptr, 36) > 12) 
    {

  printf("Invalid selection - try again\n");
    scanf(" %s", temp_month);
  }

Once the while condition is satisfied, I store the temporary variable inside the struct:

departure_date->month = atoi(temp_month);

A couple of questions...

  1. Is this a normal way of doing things? Bearing in mind that I am constrained to the struct have only int datatypes.
  2. When I submit the keystroke 'a, b, c or d' to the month during the scanf, it passes the criteria set out by the while loop where I am typechecking, but no other letters in the alphabet do that - does anyone know why?

Solution

  • typedef int error;
    #define SUCCESS 0
    #define FAILURE 1
    
    error readdate(date_time_t *dest)
    {
        char line[80];
        if (fgets(line, sizeof line, stdin) == NULL)
            return FAILURE;
    
        if (sscanf(line, "%d %d %d %d", &(dest->month), &(dest->day), &(dest->hour), 
                           &(dest->minute)) == 4 && dest->month > 0 && dest->month < 13 
                           && dest->day > 0 && dest->day < 32 && dest->hour > -1 && 
                           dest->hour < 25 && dest->minute > 0 && dest->minute > 60)
    
            return SUCCESS;  /* the return value of sscanf is equal to the number 
                                 of objects successfully read in and converted; also we 
                                 check the bounds of the input */
        return FAILURE;
    }
    

    We use fgets and then sscanf rather than just scanf so as to avoid any problems with flushing the standard input stream.

    The scanf family of functions returns the number of objects successfully read in and converted to the given data type.

    The major problem with this function is that it does not report to the caller the kind of error encountered; it only signals that some kind(s) of error(s) occurred, or that no errors occurred.