What is the reason for error while returning a structure in this C program?

前端 未结 5 1493
粉色の甜心
粉色の甜心 2020-12-21 14:54

My program intends to achieve this

(A) Write a C function named larger() that returns the later date of any two dates passed to it. For

5条回答
  •  伪装坚强ぢ
    2020-12-21 15:15

    As half-promised, a revision of Rüppell's Vulture's answer. This code struggles to avoid the repetition in the other answer — which is already reduced by comparison with the code in the question.

    There are multiple changes. Since the type only stores a single date, it is renamed Date. There is a general purpose function read_validate_number() which is used to handle the entry of each component of the date (with a separate prompt). The function returns an error/non-error status and returns the value via a pointer argument. It puts an upper bound on the number of times the user is prompted for a number. It avoids insulting the user but does report the erroneous value. The code uses a while loop rather than a do ... while loop; generally, the latter should be avoided. It would be possible to read to a newline after a failure to read a number instead of simply returning an error.

    With this function on hand, writing read_date() becomes trivial. And with read_date() on hand, the main() function simplifies.

    I'm still not keen on the interface to the function larger(); in general, I prefer the interface shown in later_date(). However, the code shows the one advantage of the larger() interface; it can identify the larger of the two dates by position in the array, whereas later_date() does that by value.

    The functions other than main() are static since they aren't used outside this file; the compiler options I use require either static functions or an extern declaration.

    On the whole, I'd prefer a less verbose interface for entering dates. I also prefer the ISO 8601 format for dates since they are unambiguous; however, that would be a user preference item in fully internationalized (and localized) code.

    #include 
    #include 
    #include 
    
    #define NUM 2
    typedef struct Date
    {
           int month;
           int day;
           int year;
    } Date;
    
    enum { MAX_ERRORS = 3 };
    
    static int read_validate_number(const char *tag, int min, int max, int *value)
    {
        int errors = 0;
        assert(min <= max);
        while (errors++ < MAX_ERRORS)
        {
            printf("Please enter the %s number (%d-%d): ", tag, min, max);
            if (scanf("%d", value) != 1)
            {
                printf("Failed to read number\n");
                return EOF;
            }
            if (*value >= min && *value <= max)
                return 0;
            printf("The value entered (%d) is outside the range %d-%d\n", *value, min, max);
        }
        printf("Too many errors entering %s\n", tag);
        return EOF;
    }
    
    static int read_date(Date *date)
    {
        if (read_validate_number("month", 1,   12, &date->month) != 0 ||
            read_validate_number("day",   1,   31, &date->day  ) != 0 ||
            read_validate_number("year",  1, 9999, &date->year ) != 0)
            return EOF;
        return 0;
    }
    
    static Date *larger(Date *more)
    {
        int days0 = (more[0].month*31)+(more[0].day)+(more[0].year*365);
        int days1 = (more[1].month*31)+(more[1].day)+(more[1].year*365);
    
        // Resist the temptation to write: return more + (days1 > days0);
        if (days1 > days0)
            return more+1;
        else
            return more+0;
    }
    
    static Date later_date(Date d1, Date d2)
    {
        int days1 = d1.day + d1.month * 31 + d1.year * 365;
        int days2 = d2.day + d2.month * 31 + d2.year * 365;
    
        if (days1 > days2)
            return d1;
        else
            return d2;
    }
    
    int main(void)
    {
        Date user[NUM];
    
        printf("Enter two dates, and the program will return the larger.\n");
        if (read_date(&user[0]) == 0 && read_date(&user[1]) == 0)
        {
            putchar('\n');
            printf("Date 1: %.4d-%.2d-%.2d\n", user[0].year, user[0].month, user[0].day);
            printf("Date 2: %.4d-%.2d-%.2d\n", user[1].year, user[1].month, user[1].day);
            Date *p_later = larger(user);
            Date  v_later = later_date(user[0], user[1]);
            printf("\nThe later date is the %s (%d/%d/%d)\n",
                   (p_later == &user[0]) ? "first" : "second",
                   p_later->month, p_later->day, p_later->year);
            printf("Later Date: %.4d-%.2d-%.2d\n", v_later.year, v_later.month, v_later.day);
        }
    
        return 0;
    }
    

    Sample output:

    Enter two dates, and the program will return the larger.
    Please enter the month number (1-12): 12
    Please enter the day number (1-31): 25
    Please enter the year number (1-9999): 2013
    Please enter the month number (1-12): 1
    Please enter the day number (1-31): 1
    Please enter the year number (1-9999): 2012
    
    Date 1: 2013-12-25
    Date 2: 2012-01-01
    
    The later date is the first (12/25/2013)
    Later Date: 2013-12-25
    

    I note that you could reduce the size of the Date structure by using unsigned char (or uint8_t) for the day and month components, and an unsigned short (or uint16_t) for the year component. However, you'd have to modify the read_date() function a bit to do so:

    #include 
    
    typedef struct Date
    {
           uint8_t  month;
           uint8_t  day;
           uint16_t year;
    } Date;
    
    static int read_date(Date *date)
    {
        int mm, dd, yyyy;
        if (read_validate_number("month", 1,   12, &mm  ) != 0 ||
            read_validate_number("day",   1,   31, &dd  ) != 0 ||
            read_validate_number("year",  1, 9999, &yyyy) != 0)
            return EOF;
        date->month = mm;
        date->day   = dd;
        date->year  = yyyy;
        return 0;
    }
    

    At some point, you might want to prevent someone entering the 31st of February (but remember that there was once a 30th of February — in Sweden, in 1712; or there again, maybe you don't need to remember that).

提交回复
热议问题