Thread: validating inputs in code

  1. #1
    Registered User
    Join Date
    Oct 2013
    Posts
    7

    validating inputs in code

    i have a code which compares between these two variables. date1 and date2. The program runs when the user input two correct dates eg: 20/10/2003 20/14/2004 then it will read and display values in between the date. That means if the user enters other characters like alphabets or other weird characters the program will prompt an error and not run.

    Only with the correct input(int) then it can run. how can i implement this in that case? probably in real expressions or switch case? thanks

    this is my code:





    /*
    * date_compare compares two dates, returning <0, 0, >0 if
    * date1<date2, date1==date2, date1>date2, respectively
    */
    int date_compare(Date *date1, Date *date2)
    {
    if(date1->year < date2->year)
    {
    //printf("Year is smaller");
    return -1;
    }
    else if (date1->year > date2->year)
    {
    //printf("Year is bigger");
    return 1;
    }
    else
    {
    if (date1->month < date2->month)
    {
    //printf("Month is smaller");
    return -1;
    }

    else if (date1->month > date2->month)
    {
    //printf("Month is bigger");
    return 1;
    }
    else
    {
    if(date1->day < date2->day)
    {
    //printf("Day is smaller");
    return -1;
    }
    else if(date1->day > date2->day)
    {
    //printf("Day is bigger");
    return 1;
    }
    else
    {
    //printf("equal");
    return 0;
    }

    }
    }
    }
    /*
    * date_destroy returns any storage associated with `d' to the system
    */
    void date_destroy(Date *d){
    if(d != NULL){
    free(d);
    }
    }




    [/CODE]
    Last edited by newtocprogram; 10-29-2013 at 12:26 AM.

  2. #2
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    FYI, they're called regular expressions, not real expressions. I don't think they're available in standard C, but there is a POSIX extension supporting them and there are 3rd party libraries that provide regex functions.

    There are several other options as well:
    1. If available, use strptime.
    2. Split the string using strtok. Use strtol or strtoul to convert to int/long, it has better error detection (atoi has none). You can use the endptr parameter to check if there is garbage at the end of datestr.
    3. Use sscanf to parse datestr and extract the year, month and day. You will need to make sure there is no garbage at the end of your datestr.

    If you go for option 2 or 3, you need to remember that not all months have 31 days, some have 30 and February has 28 (29 in a leap year). A switch statement here is good for checking max day based on the month, especially since you can take advantage of fall-through (see below). Google will turn up formulas for determining leap year, to help you figure out if February should have 28 or 29 days for the given year.
    Code:
    switch (month) {
        case 1:  // fall-through
        case 3:  // fall-through
        case 5:  // fall-through
        ...
        case 12:
            max_days = 31;
            break;
    
        case 4:  // fall-through
        case 6:  // fall-through
        ...
    }
    if (day > max_days)
        printf("Bad date, month %d has %d days", month, max_days);  // usually a good idea to tell the user why their input was invalid
    It's a good idea to leave a comment stating that you explicitly want the cases to fall through, just to be clear you didn't forget a break;
    Last edited by anduril462; 10-29-2013 at 12:12 AM.

  3. #3
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    20/14/2004 - does not looks like valid date

    strncopy could leave your string without nul-terminator - so you need to put it manually before applying and string manipulating routines that rely on nul-terminator existense

    And I personally prefer using strtoul for parsing such data over strtok - with it you do not need local copy

    In case of failed parsing or wrong data - you have a memory leak - better move your memory allocation to the line 32

    Code:
    Date *date_duplicate(Date *d)
    {
        Date *cloneDate = malloc(sizeof(*cloneDate));
        if(cloneDate )
            *cloneDate = *d;
         
        return cloneDate;
    }
    looks easier, checks return value of malloc and you do not need cast malloc in C - read FAQ
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  4. #4
    Registered User
    Join Date
    Oct 2013
    Posts
    7
    Quote Originally Posted by anduril462 View Post
    FYI, they're called regular expressions, not real expressions. I don't think they're available in standard C, but there is a POSIX extension supporting them and there are 3rd party libraries that provide regex functions.

    There are several other options as well:
    1. If available, use strptime.
    2. Split the string using strtok. Use strtol or strtoul to convert to int/long, it has better error detection (atoi has none). You can use the endptr parameter to check if there is garbage at the end of datestr.
    3. Use sscanf to parse datestr and extract the year, month and day. You will need to make sure there is no garbage at the end of your datestr.

    If you go for option 2 or 3, you need to remember that not all months have 31 days, some have 30 and February has 28 (29 in a leap year). A switch statement here is good for checking max day based on the month, especially since you can take advantage of fall-through (see below). Google will turn up formulas for determining leap year, to help you figure out if February should have 28 or 29 days for the given year.
    Code:
    switch (month) {
        case 1:  // fall-through
        case 3:  // fall-through
        case 5:  // fall-through
        ...
        case 12:
            max_days = 31;
            break;
    
        case 4:  // fall-through
        case 6:  // fall-through
        ...
    }
    if (day > max_days)
        printf("Bad date, month %d has %d days", month, max_days);  // usually a good idea to tell the user why their input was invalid
    It's a good idea to leave a comment stating that you explicitly want the cases to fall through, just to be clear you didn't forget a break;

    thanks for the prompt response, do i add the switch case statement under my date_compare function? possible to do a bit of psudocode here? i will try to implement it myself

  5. #5
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    Before considering regular expressions dont underestimate the power of good old scanf, you can check make sure the number of input parameters and form "mm/dd/yyyy" etc is correct. If it's not, you can stop already because its not a correct date. Otherwise move on to check other things like numerical ranges, leap years etc. Then place the items like day, month, year into your date structure.

    Code:
    // read a date like "mm/dd/yyyy" where mm is a month 1 <= mm <= 12,
    // dd is a day 1 <= dd <= 31 and yyyy is a year 1900 <= yyyy <= 9999
    // return true if correct format and valid date; false otherwise
    bool valid(const char *datestr)
    {
        int month, day, year;
        char dummy;
        
        if (sscanf(datestr, " %d/%d/%d %c", &month, &day, &year, &dummy) != 3)
            return false;
        if (month < 1 || month > 12)
            return false;
        if (day < 1 || day > 31)
            return false;
        if (year < 1 || year > 9999)
            return false;
        return true;
    }
    
    int main()
    {
        printf("%s is %s\n", "12/25/2013/", (valid("12/25/2013/") ? "valid" : "invalid!"));
        printf("%s is %s\n", " 12/25/2013", (valid(" 12/25/2013") ? "valid" : "invalid!"));
        printf("%s is %s\n", " 12/25/2013 !", (valid(" 12/25/2013 !") ? "valid" : "invalid!"));
        printf("%s is %s\n", "25/12/2013", (valid("25/12/2013") ? "valid" : "invalid!"));    
        return 0;
    }
    In the example the leading blank in the scanf format allows 0 or more leading blanks in the input. The dummy parameter prevents non-blank inputs which are invalid like "!"

  6. #6
    Registered User
    Join Date
    Oct 2013
    Posts
    7
    im having an error while doing this code u provided.. it doesnt recognise createDate why is that so

    Code:
    Date *date_create(char *datestr) {
    
    
        int day, month, year;
        Date *createDate = (Date *) malloc(sizeof(Date));
        char copyDateStr[20]; //a array to copy dateStr
        strncpy(copyDateStr, datestr, 20); //copy dateStr to copyDateStr
    
        day = atoi(strtok(copyDateStr, "/"));
        month = atoi(strtok(NULL, "/"));
        year = atoi(strtok(NULL, "/"));
        
        char dummy;
         
        if (sscanf(datestr, " %d/%d/%d %c", &month, &day, &year, &dummy) != 3)
            return false;
        if (month < 1 || month > 12)
            return false;
        if (day < 1 || day > 31)
            return false;
        if (year < 1 || year > 9999)
            return false;
        return true;
    }
    
        createDate->day = day;
        createDate->month = month;
        createDate->year = year;
        
    
    
            return createDate;
        
    }

  7. #7
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    Where is your definition of Date? Is it a struct. Also it seems you have an extra closing brace at the end of your input. Also if you have a problem compiling you wont get far if you dont say what the exact error was. I mean what is the message that is printed

  8. #8
    Registered User
    Join Date
    Oct 2013
    Posts
    7
    as in it doesnt recognise the createDate: this declaration has no storage type or type specifier
    there is an error in return true too : error value return type does not match the function type

    these are the two errors

  9. #9
    Registered User
    Join Date
    Dec 2012
    Posts
    307
    the leapyear check i use is
    Code:
    if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
    if true, it is a leap, if not true it is not!

    this saves a handful of if if else checks!

    good luck with the rest!

  10. #10
    Registered User
    Join Date
    Oct 2013
    Posts
    7
    doest work actually... for the leap year

  11. #11
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Please post all your code, exactly as it is right now. It's hard for us to figure out what problems you are having with createDate or leap years if you don't provide us with createDate and all relevant definitions (e.g. the Date type), or all code relevant to your leap year calculation. Besides, your code has almost certainly changed since the last time you posted code. Also, you need to be specific when you describe your problem. Is it a problem compiling? Then copy-paste all the error messages with line numbers. Is it a problem when running the code? Then describe the symptoms: program crashes, no output, incorrect output, etc. Provide us with the exact input you give the program, the (incorrect) output you are seeing and the correct output you expect to see.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Validating Inputs: Only Numbers
    By tomeatworld in forum C Programming
    Replies: 21
    Last Post: 11-07-2010, 02:05 PM
  2. How to handle inputs if the user inputs the wrong thing
    By bassist11 in forum C Programming
    Replies: 5
    Last Post: 09-22-2010, 04:28 AM
  3. Problems validating
    By ebenezum in forum C Programming
    Replies: 1
    Last Post: 05-18-2008, 12:01 PM
  4. Can someone help me with validating?
    By Maria Jordan in forum C Programming
    Replies: 5
    Last Post: 03-27-2005, 04:41 AM
  5. Validating Numbers only
    By shacapoo in forum C Programming
    Replies: 25
    Last Post: 12-11-2004, 11:13 PM