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

前端 未结 5 1476
粉色の甜心
粉色の甜心 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 <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    
    #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 <stdint.h>
    
    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).

    0 讨论(0)
  • 2020-12-21 15:16

    @Rüppell'sVulture You highlighted his errors but the code is too erroneous. I have worked on a simpler solution of it. Have a look.

    @iMPose27 Please see the following code and let me know in case you run in some difficulty

    // includes
    #include <stdio.h>
    #include <string.h>
    
    // macros
    #define NUM 2
    
    // structure Definitions
    struct Dates
    {
           int month;
           int day;
           int year;
    };
    
    // typedefs
    typedef struct Dates DATES;
    
    // function declarations
    DATES* larger(DATES[NUM]);
    
    // function definitions
    int main(int argc, char* argv[])
    {
        DATES user[NUM];    // array of NUM DATES
        DATES *result=NULL;
        int i=0;
        printf("\nPlease Enter Two Dates, The program will evaluate and return the later date of the two dates passed to it\n\n");
        for(;i<NUM;i++)   
        {    
            printf("For Date %d\n",i+1);
    
            do{
                 printf("Please enter the month, 1-12:\t");
                 scanf("%d", &user[i].month);
            }while (user[i].month < 1 || user[i].month > 12);
    
            do{
                  printf("Please enter the day, 1-31:\t");
                  scanf("%d", &user[i].day);
            }while (user[i].day < 1 || user[i].day > 31);
    
            do{           
                  printf("Please enter the year: \t");
                  scanf("%d)", &user[i].year);
            }while (user[i].year < 1);
    
            printf("\nDate %d entered: %d/%d/%d.\n\n", i+1, user[i].month, user[i].day, user[i].year);
    
        } 
    
        if((result=larger(user))==NULL)
            printf("The two dates passed, date1: %d/%d/%d and date2: %d/%d/%d are the same.\n",user[0].month, user[0].day, user[0].year, user[1].month, user[1].day, user[1].year); 
        else
            printf("%d/%d/%d is the later date of the two dates passed\n",result->month, result->day, result->year); 
    
        return 0;
    }
    
    DATES* larger(DATES more[NUM])
    {        
          int days0, days1;
    
          days0 = (more[0].month*31)+(more[0].day)+(more[0].year*365);
          days1 = (more[1].month*31)+(more[1].day)+(more[1].year*365);
    
          if (days0 > days1)
            return more;        
          else if (days1 > days0)
            return more+1;
          else
            return 0;       
    }
    
    0 讨论(0)
  • 2020-12-21 15:29
    DATES result[NUM] = larger(DATES user[NUM]);
    

    What's this intended to do? DATES result[NUM] declares an array of DATES. (But each DATES contains only one date, which is confusing.) But despite being an array, it's initialized with a single object, the return value from larger. The argument to larger, DATES user[NUM], appears to be declaring user, a variable which already exists. It looks like you're trying to clarify to the compiler that user is an array of dates, but DATES doesn't go there and [NUM] appears to be indexing into the array, which you don't want.

    Probably what you want is

    DATES result = larger( user );
    

    Also there are some serious style issues which will cause trouble later:

    • Array types for function parameters as in DATES larger(DATES[NUM]); are converted to pointers. On that line, NUM does nothing and the declaration is the same as DATES larger( DATES * );. Despite what some teachers may say, pointers and arrays are not the same thing. When the distinction is important, this style causes confusion. Use DATES larger( DATES * ) instead.

    • It doesn't make sense to capitalize DATES. Caps usually indicate a preprocessor macro.

    • Preprocessor macros are like a sledgehammer. Using them for simple numeric constants is less elegant than constructs like const int num = 2; or enum { num = 2 };

    • Descriptive variable names like input_limit and user_input would be better than num and user.

    • Don't rely on uninitialized data. user[0].month might be 6 after user is defined but not initialized. Always write a value before reading.

    • Braces should be kept visible. Grouping braces closely with the first and last words of the loop hides them, which is good if you think they're ugly, but then it's very very easy to incorrectly add a line to the loop, producing a hard-to-debug flow control error.

    0 讨论(0)
  • 2020-12-21 15:29

    There are many logical and syntactical errors in your program.I corrected all the syntactical part and must point out the major flaw in the logic of the while loops.You seem to have confused > and < in the following conditions:

    while (user[0].month < 1 || user[0].month > 12);  //Wrong
    
    while (user[0].month > 1 || user[0].month < 12);  //Correct
    

    Months are less than 1 or greater than 12 only in Mars,but on earth,due to pollution,they are between 1 and 12.I have corrected those and pointed that out in comments.And you should use a for loop instead of repeating the same thing for each element of the array DATES

    AAAAAGHHH It was so full of errors.Here's the working version.It achieves the 2 objectives that you mentioned in your question-Ask user for 2 dates,and find which one is bigger/later.I am not including BC, only AD years.Won't matter unless you want to know if some neanderthal man was born earlier or later than any of us.And the function larger returns a pointer to the answer,which is stored in a new datastructure largerdate and printed out.

    Here's a brief explanation for the revised code:

    The outer for loop automates the input for each date.There's no need to repeat the same code for each date as you did.If the number of dates goes up,it will be tedious.Further,the do-while loop asks the user for the date in the range specified.If that jerk makes an error,he is yelled at and the condition of that loop makes sure the jerk has to enter again.The two dates are stored in an array user[] and the base address of type DATE* is passed as an argument to the function larger() which compares the two dates and returns a pointer of type DATE* to the larger date.This is used to store the greater date in a new datastructure called largerdate and then printed out.

    #include <stdio.h>
    #define NUM 2
    struct Dates
    {
           int month;
           int day;
           int year;
    };
    typedef struct Dates DATES;
    DATES  *larger(DATES*);
    //DATES more;     //Not needed as you are doing the same in function definition
    
    int main(void)
    {
        DATES user[NUM],largerdate;
        int i;
         printf("You will enter two dates, and the program will return the larger.\n");
        for(i=0;i<NUM;i++)   //for loop is handy when NUM increases.
           {
               do
               {
            printf("\nPlease enter the month number %d, 1-12:\n ",i);
             scanf("%d", &user[i].month);
             if(user[i].month<1||user[i].month>12)
             printf("I told you enter a number between 1-12 JERK!!\n");
               }while(user[i].month<1||user[i].month>12);
              do
               {
            printf("\nPlease enter the day number %d, 1-31:\n ",i);
             scanf("%d", &user[i].day);
             if(user[i].day<1||user[i].day>31)
             printf("I told you enter a number between 1-31 JERK!!\n");
               }while(user[i].day<1||user[i].day>31);
               do
               {
            printf("\nPlease enter the year number %d,greater than one:\n ",i);
             scanf("%d", &user[i].year);
             if(user[i].year<1)
             printf("I told you enter a number greater than 1 JERK!!\n");
               }while(user[i].year<1);
        printf("\nDate number %d entered is: %d/%d/%d.\n", i+1,user[i].month, user[i].day, user[i].year);
    
       } //for loop ends.It avoids repeating the same thing for DATES[1]
    
    
       largerdate=*larger(user);
       printf("\n\nThe larger/later date is %d/%d/%d\n",largerdate.month,largerdate.day,\
       largerdate.year);
    
    
        system("pause");
        return 0;
    }
    
    DATES *larger(DATES *more)
    {
          int days0;
          int days1;
    
          days0 = (more[0].month*31)+(more[0].day)+(more[0].year*365);
          days1 = (more[1].month*31)+(more[1].day)+(more[1].year*365);
    
          if (days1 > days0)
         return more+1;
          else
          return more;
    }
    
    0 讨论(0)
  • 2020-12-21 15:31

    There are several little corrections needed in this program but your main problem is the difference between while and do while loops.

    while(<condition>)
    {
      //Something
    }
    

    and

    do
    {
      //Something
    }
    while(<condition>)
    

    differ in the fact that do while enters the loop atleast once and then checks for the condition to be satisfied. But while on the other hand never enters the loop if the condition is not satisfied. So in a nutshell you aren't entering the while loop and hence aren't reading anything from the user.

    0 讨论(0)
提交回复
热议问题