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

心不动则不痛 提交于 2020-01-10 05:35:08

问题


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 example, if the dates 10/9/2001 and 11/3/2001 are passed to larger(), the second date would be returned.

(B) Create the larger() function that was written for (A) in a complete unit. Store the date structure returned by larger() in a separate date structure and display the member values of the returned data structure.

I am working on this problem for my C Language course. I had everything going well (I thought), except that I kept getting "The larger date is: 0/0/0" no matter what I entered. So I started tinkering, and now I cannot get rid of the syntax error, or figure out my 0/0/0 problem. Obviously the dates aren't making it back through. I'm still pretty new at this (and very new at structs), so any help would be awesome!

The line that's giving me the syntax error is near the bottom of main():

DATES result[NUM] = larger(DATES user[NUM]);

The code in full:

#include <stdio.h>
#define NUM 2
struct Dates
{
       int month;
       int day;
       int year;
};
typedef struct Dates DATES;
DATES larger(DATES[NUM]);
DATES more;
int main()
{
    DATES user[NUM];

    printf("You will enter two dates, and the program will return the larger.\n");
    while (user[0].month < 1 || user[0].month > 12)
         {printf("\nPlease enter the first month, 1-12: ");
         scanf("%d", &user[0].month);}
    while (user[0].day < 1 || user[0].day > 31)
          {printf("\nPlease enter the first day, 1-31: ");
          scanf("%d", &user[0].day);}
    while (user[0].year < 1)
          {printf("\nPlease enter the first year: ");
          scanf("%d)", &user[0].year);}
    printf("\nDate entered: %d/%d/%d.\n", user[0].month, user[0].day, user[0].year);

    while (user[1].month < 1 || user[1].month > 12)
         {printf("\nPlease enter the first month, 1-12: ");
         scanf("%d", &user[1].month);}
    while (user[1].day < 1 || user[1].day > 31)
          {printf("\nPlease enter the first day, 1-31: ");
          scanf("%d", &user[1].day);}
    while (user[1].year < 1)
          {printf("\nPlease enter the first year: ");
          scanf("%d)", &user[1].year);}
    printf("\nDate entered: %d/%d/%d.\n\n", user[1].month, user[1].day, user[1].year);

    DATES result[NUM] = larger(DATES user[NUM]);  /* Problem here */

    printf("The larger date is %d/%d/%d.\n\n", result[0].month, result[0].day, result[0].year);
    system("pause");
    return 0;
}

DATES larger(DATES more[NUM])
{        
      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)
         {more[0] = more[1];}

return (more[0]);
}

回答1:


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.




回答2:


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.




回答3:


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;
}



回答4:


@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;       
}



回答5:


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).



来源:https://stackoverflow.com/questions/16350807/what-is-the-reason-for-error-while-returning-a-structure-in-this-c-program

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!