在此C程序中返回结构时出错的原因是什么?

我的计划打算实现这一目标

(A)编写一个名为larger()的C函数,它返回传递给它的任何两个日期的后期日期。 例如,如果将日期10/9/2001和11/3/2001传递给greater larger() ,则将返回第二个日期。

(B)在完整单元中创建为(A)编写的large()函数。 将large()返回的日期结构存储在单独的日期结构中,并显示返回的数据结构的成员值。

我正在为我的C语言课程研究这个问题。 我一切顺利(我想),除了我不断得到“更大的日期是:0/0/0”,无论我输入什么。 所以我开始修补,现在我无法摆脱语法错误,或弄清楚我的0/0/0问题。 显然日期并没有让它重新开始。 我对此仍然很陌生(并且在结构上非常新),所以任何帮助都会很棒!

给我语法错误的行靠近main()的底部:

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

代码全部:

 #include  #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  12) {printf("\nPlease enter the first month, 1-12: "); scanf("%d", &user[0].month);} while (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  12) {printf("\nPlease enter the first month, 1-12: "); scanf("%d", &user[1].month);} while (user[1].day  31) {printf("\nPlease enter the first day, 1-31: "); scanf("%d", &user[1].day);} while (user[1].year  days0) {more[0] = more[1];} return (more[0]); } 

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

这是打算做什么的? DATES result[NUM]声明一个DATES数组。 (但每个DATES只包含一个日期,这很令人困惑。)但是尽管是一个数组,它是用一个对象初始化的,返回值来自largerlarger DATES user[NUM]的参数似乎是声明user ,这是一个已经存在的变量。 看起来你正试图向编译器说明user是一个日期数组,但是DATES不会去那里, [NUM]似乎正在索引到你不想要的数组中。

可能你想要的是什么

 DATES result = larger( user ); 

还有一些严重的样式问题会在以后引起麻烦:

  • 函数参数的数组类型,如DATES larger(DATES[NUM]); 被转换为指针。 在那一行, NUM什么都不做,声明与DATES larger( DATES * ); 。 尽管有些教师可能会说,指针和数组并不是一回事。 当区别很重要时,这种风格会引起混淆。 请改用DATES larger( DATES * )

  • DATES资本化是没有意义的。 Caps通常表示预处理器宏。

  • 预处理器宏就像一把大锤。 将它们用于简单的数字常量不如const int num = 2;这样的结构优雅const int num = 2;enum { num = 2 };

  • 诸如input_limituser_input类的描述性变量名称将优于numuser

  • 不要依赖未初始化的数据。 user[0].month可能在user定义但未初始化后为6。 在阅读之前总是写一个值。

  • 大括号应该保持可见。 用循环的第一个和最后一个字紧密地分组括号隐藏它们,如果你觉得它们很难看,这很好,但是很容易错误地在循环中添加一行,产生一个难以调试的流量控制错误。

你的程序中有许多逻辑和语法错误。我纠正了所有语法部分,必须指出while循环逻辑中的主要缺陷。你似乎在以下条件中混淆了><

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

火星只有几个月不到1或大于12 ,但在地球上,由于污染,它们在112之间。我已经纠正了这些并在评论中指出了这一点。你应该使用for循环而不是重复对于数组DATES每个元素都是一样的

AAAAAGHHH它充满了错误。这是工作版本。它实现了你在问题中提到的2个目标 - 询问用户2个日期,找到哪个更大/更晚。我不包括BC ,只有AD年。除非你想知道某个尼安德特人是否比我们中的任何一个出生得晚或晚,否则无关紧要。函数large返回一个指向答案的指针,该指针存储在一个largerdate的新数据结构中并打印出来。

以下是修订后代码的简要说明:

外部for循环自动化每个日期的输入。没有必要为每个日期重复相同的代码。如果日期数量增加,那将是乏味的。此外, do-while循环要求用户指定范围内的日期。如果该混蛋发生错误,他会被大喊并且该循环的条件确保该混蛋必须再次输入。两个日期存储在数组user[]和类型的基地址中DATE*作为参数传递给函数greater larger() ,该函数比较两个日期并将类型为DATE*的指针返回到更大的日期。这用于将更大的日期存储在名为largerdate的新数据结构中,然后打印出来。

 #include  #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;i12) 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; } 

这个程序需要几个小的修正,但你的主要问题是while和while循环之间的区别。

 while() { //Something } 

 do { //Something } while() 

在进入至少一次循环然后检查要满足的条件的情况下不同。 但另一方面,如果条件不满足,则永远不会进入循环。 因此,简而言之,您不会进入while循环,因此不会从用户那里读取任何内容。

@Rüppell’sVulture你突出了他的错误,但代码太错了。 我已经研究过一个更简单的解决方案。 看一看。

@ iMPose27请参阅以下代码,如果遇到困难,请告诉我

 // includes #include  #include  // 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 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; } 

正如一半承诺的那样,修改了吕佩尔的秃鹰的答案 。 这段代码努力避免在另一个答案中重复 – 与问题中的代码相比,这已经减少了。

有多种变化。 由于类型仅存储单个日期,因此将其重命名为Date 。 有一个通用函数read_validate_number() ,用于处理日期的每个组件的条目(带有单独的提示)。 该函数返回错误/非错误状态,并通过指针参数返回值。 它为用户提示输入数字的次数设置了上限。 它避免了侮辱用户,但确实报告了错误的价值。 代码使用while循环而不是do ... while循环; 一般来说,应该避免后者。 在读取数字失败而不是简单地返回错误之后,可以读取换行符。

有了这个function,写read_date()变得微不足道。 并且手头有read_date()main()函数简化了。

我仍然不热衷于函数接口larger() ; 一般来说,我更喜欢later_date()显示的界面。 但是,代码显示了larger()接口的一个优点; 它可以通过数组中的位置识别两个日期中较大的日期,而later_date()值进行later_date()

main()以外的函数是静态的,因为它们不在此文件之外使用; 我使用的编译器选项需要static函数或extern声明。

总的来说,我更喜欢用于输入日期的简洁界面。 我也更喜欢ISO 8601格式的日期,因为它们是明确的; 但是,这将是完全国际化(和本地化)代码中的用户首选项。

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

样本输出:

 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 

我注意到,您可以通过对Datemonth组件使用unsigned char (或uint8_t )以及为year组件使用unsigned short (或uint16_t )来减小Date结构的大小。 但是,您必须稍微修改read_date()函数:

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

在某些时候,你可能想要阻止某人进入2月31日(但请记住,曾经是2月30日 – 在瑞典,在1712年;或者再次,也许你不需要记住它)。