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

时间:2013-05-03 02:45:19

标签: c syntax struct

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

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

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

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

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

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

完整的代码:

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

5 个答案:

答案 0 :(得分:1)

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

这是打算做什么的? DATES result[NUM]声明了一个DATES数组。 (但是每个DATES只包含一个日期,这很令人困惑。)但是尽管是一个数组,它还是用一个对象初始化,返回值来自largerlargerDATES 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;enum { num = 2 };

  • 这样的结构优雅
  • input_limituser_input等描述性变量名称将优于numuser

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

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

答案 1 :(得分:0)

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

while(<condition>)
{
  //Something
}

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

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

答案 2 :(得分:0)

你的程序中存在许多逻辑和语法错误。我纠正了所有语法部分,必须指出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 年。除非你想知道一些尼安德特人是否比我们任何人早出生或晚出生,否则无关紧要。 larger返回指向答案的指针,该答案存储在新的数据结构largerdate中并打印出来。

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

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

largerdate

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

一半承诺,修改Rüppell's Vultureanswer。这段代码努力避免在另一个答案中重复 - 与问题中的代码相比,这已经减少了。

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

有了这个功能,写read_date()变得微不足道。有了read_date()main()函数就会简化。

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

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

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

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

示例输出:

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

我注意到,对于Dateunsigned char组件使用uint8_t(或day)可以缩小month结构的大小,以及unsigned short组件的uint16_t(或year)。但是,您必须稍微修改read_date()函数:

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

在某些时候,你可能想要阻止某人进入2月31日(但记得曾经有一次30th of February - 在瑞典,在1712年;或者在那里,也许你不需要记住这一点)。