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