First program in C - what is going on with function returns?

B

ben.carbery

Hi,

I have just written a simple program to get me started in C that
calculates the number of days since your birthdate.
One thing that confuses me about the program (even though it works) is
how global variables and function returns work...

For example, I have a global array "char datestring[80];" which is
defined in the function speakdate. speakdate just converts a set of
integers (date variables) to a string.

The main program then does:
"printf ("The current date is:
%s\n\n",speakdate(cdate,cmonth,cyear));"

And correctly prints the value of datestring.
What I don't get is why this works since I haven't explicitly told
speakdate to return datestring.
I figured by default it would return nothing at all.

Full code below. By the way any other tips on my code would be welcomed
and appreciated!

cheers,

Ben C

Code:
char datestring[80];
/* dim is 'days in month'*/
int dim;

speakdate(int d, int m, int y)
{

char stdate[5],stmonth[10],styear[5];

     sprintf( stdate, "%d", d);
     sprintf( styear, "%d", y);

     switch (d) {
            case 1 :
            case 21 :
            case 31 : strcat(stdate,"st ");
                 /*printf("The date is %s\n",stdate);*/
                 break;
            case 2 :
            case 22 : strcat(stdate,"nd ");
                 /*printf("The date is %s\n",stdate);*/
                 break;
            case 3 :
            case 23 : strcat(stdate,"rd ");
                 /*printf("The date is %s\n",stdate);*/
                 break;
            case 4 :
            case 5 :
            case 6 :
            case 7 :
            case 8 :
            case 9 :
            case 10 :
            case 11 :
            case 12 :
            case 13 :
            case 14 :
            case 15 :
            case 16 :
            case 17 :
            case 18 :
            case 19 :
            case 24 :
            case 25 :
            case 26 :
            case 27 :
            case 28 :
            case 29 :
            case 30 : strcat(stdate,"th ");
                 /*printf("The date is %s\n",stdate);*/
                 break;
            default : strcat(stdate,"Invalid ");
                 /*printf("The date is %s\n",stdate);*/
                 break;
     }

     switch (m) {
            case 1 : strcpy(stmonth,"January");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
            case 2 : strcpy(stmonth,"February");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
            case 3 : strcpy(stmonth,"March");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
            case 4 : strcpy(stmonth,"April");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
            case 5 : strcpy(stmonth,"May");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
            case 6 : strcpy(stmonth,"June");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
            case 7 : strcpy(stmonth,"July");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
            case 8 : strcpy(stmonth,"Aug");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
            case 9 : strcpy(stmonth,"Sep");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
            case 10 : strcpy(stmonth,"Oct");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
            case 11 : strcpy(stmonth,"Nov");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
            case 12 : strcpy(stmonth,"Dec");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
            default : strcpy(stmonth,"Invalid");
                 /*printf("The month is %s\n",stmonth);*/
                 break;
     } /* end of switch */

     strcpy(datestring,stdate);
     strcat(datestring,stmonth);
     strcat(datestring," ");
     strcat(datestring,styear);
     strcat(datestring,".");
     /*printf("%s",datestring);*/

}

int countdays(int bd, int bm, int by, int cd, int cm, int cy)
{

int month,year;

     int daysalive = 0;

     /* count the days in whole years */
     for (year=by+1;year<cy;year=++year) {
          if (year==2000) {
               daysalive = daysalive + 365;
               /*printf("year is %d, adding 365, daysalive counted so
far is %d\n",year,daysalive);*/
          }
          else {
               if (fmod(year,4)==0) {
                    daysalive = (daysalive + 366);
                    /*printf("year is %d, adding 366, daysalive counted
so far is %d\n",year,daysalive);*/
               }
               else {
                    daysalive = (daysalive + 365);
                    /*printf("year is %d, adding 365, daysalive counted
so far is %d\n",year,daysalive);*/
               }
          }
     }
     /*printf("%d\n",daysalive);*/

     /* days in whole months this year */
     for (month=cm-1;month>0;--month) {
         daysalive = (daysalive + (monthswitch(month,year)));
         /*printf("adding %d, month is
%d\n",(monthswitch(month,year)),month);*/
     }
     /*printf("%d\n",daysalive);*/

     /* days so far in the current month */
     daysalive = (daysalive + cd);
     /*printf("%d\n",daysalive);*/

     /* days in whole months in birth year */
     for (month=bm+1;month<13;++month) {
         daysalive = (daysalive + (monthswitch(month,year)));
     }
     /*printf("%d\n",daysalive);*/

     /* days in birth month */
     daysalive = (daysalive + (monthswitch(bm,by)) - bd);
     /*printf("%d\n",daysalive);*/

     return daysalive;

}

int monthswitch(int month,int year) {
     switch (month) {
          case 4 :
          case 6 :
          case 9 :
          case 11 :
          case 12 : dim = 30;
               break;
          case 1 :
          case 3 :
          case 5 :
          case 7 :
          case 8 :
          case 10 : dim = 31;
               break;
          case 2 :
               if (year==2000) {
                    dim = 28;
                    break;
               }
               if (fmod(year,4)==0) {
                    dim = 29;
                    break;
               }
               else
                    dim = 28;
                    break;
     }
     return dim;
}

main(void)
{

int bdate,bmonth,byear;

     printf ("Please enter your birth date (d/m/yyyy):\n");
     scanf  ("%d/%d/%d",&bdate,&bmonth,&byear);
     printf ("Your date of birth is
%s\n\n",speakdate(bdate,bmonth,byear));

int cdate,cmonth,cyear;

     printf ("Please enter the current date (d/m/yyyy):\n");
     scanf  ("%d/%d/%d",&cdate,&cmonth,&cyear);
     printf ("The current date is:
%s\n\n",speakdate(cdate,cmonth,cyear));

printf ("Congratulations! You were born a total of %d days
ago.\n",countdays(bdate,bmonth,byear,cdate,cmonth,cyear));
     
}
 
B

Bill Pursell

Hi,

I have just written a simple program to get me started in C that
calculates the number of days since your birthdate.
One thing that confuses me about the program (even though it works) is
how global variables and function returns work...

For example, I have a global array "char datestring[80];" which is
defined in the function speakdate. speakdate just converts a set of
integers (date variables) to a string.

The main program then does:
"printf ("The current date is:
%s\n\n",speakdate(cdate,cmonth,cyear));"

And correctly prints the value of datestring.
What I don't get is why this works since I haven't explicitly told
speakdate to return datestring.
I figured by default it would return nothing at all.

By default, it returns an int. I'm not certain, but I believe what is
happening is that the return value of the last strcat is being returned
from speakdate. strcat is returning a char *, and the char * is being
cast to an int. You're program is working because on your machine int
and char * probably have the same size.

To avoid this problem, you should explicitely specify the return type
of the function, and explicitely return a value.
 
K

Kelsey Bjarnason

[snips]

Full code below. By the way any other tips on my code would be welcomed
and appreciated!


You said "full code" - but I don't see the proper includes here.
char datestring[80];
/* dim is 'days in month'*/
int dim;

speakdate(int d, int m, int y)

What type is being returned? If you meant "nothing", specify void.
strcpy(datestring,stdate);
strcat(datestring,stmonth);

At the end of the function, the global datestring has a date. So far so
good.

int countdays(int bd, int bm, int by, int cd, int cm, int cy) {

int month,year;

int daysalive = 0;

/* count the days in whole years */
for (year=by+1;year<cy;year=++year) {

You probably don't want year=++year, but simply ++year
if (fmod(year,4)==0) {

At a guess, you simply want the modulus operand - % - here.
main(void)

int main(void)
{

int bdate,bmonth,byear;

printf ("Please enter your birth date (d/m/yyyy):\n"); scanf
("%d/%d/%d",&bdate,&bmonth,&byear);
printf ("Your date of birth is %s\n\n",speakdate(bdate,bmonth,byear));

speakdate(), as written, returns nothing, so treating it as if it does is
an error. That you get any output at all is simply a matter of accident.
printf ("Congratulations! You were born a total of %d days
ago.\n",countdays(bdate,bmonth,byear,cdate,cmonth,cyear));


[/code]

No close brace, no return. Despite the claim of "full code below",
there's no way this could be the full code, as it cannot compile.

That said, you should also turn your compiler's warning level to maximum,
and pay attention to the warnings.
 
B

ben.carbery

I think I did this since I couldn't figure out how to return a string.

"char speakdate(int d, int m, int y) {" works ok, but

"char[whatever] speakdate(int d, int m, int y) {" didn't.

Is there another syntax to use here?
 
B

ben.carbery

Thanks for the detailed response!
What type is being returned? If you meant "nothing", specify void.

As per last reply, I want to return a string, but am not sure of the
syntax for returning arrays...
At a guess, you simply want the modulus operand - % - here.

so... "if((year%4)==0)" ?
int main(void)

on a related note, is there a difference between "int main (void)" and
"int main ()" ?
speakdate(), as written, returns nothing, so treating it as if it does is
an error. That you get any output at all is simply a matter of accident.

should be able to fix this if i can return an array.
there's no way this could be the full code, as it cannot compile.

Hmmm, this was the full code I was using, compiling ok with bloodshed
dev-c++ on windows (a gcc based compiler). Can't see anything obvious
to raise the logging level, or to expert stricter code...
 
B

Bill Pursell

Thanks for the detailed response!



As per last reply, I want to return a string, but am not sure of the
syntax for returning arrays...

You can't return an array, but you can return a pointer to the first
entry.


#include <stdio.h>
#include <string.h>
#define MAX_LENGTH 256

char * foo(void)
{
static char ret[MAX_LENGTH];
strncpy(ret, "test", MAX_LENGTH);
return ret;
}

int main(void)
{
printf("%s\n", foo());
return 0;
}
 
H

Herbert Rosenau

I think I did this since I couldn't figure out how to return a string.

"char speakdate(int d, int m, int y) {" works ok, but

char *speakdate(int d, int m, int y);

will do the trick. You should return a pointer the the string you've
builded.

--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 
H

Herbert Rosenau

on a related note, is there a difference between "int main (void)" and
"int main ()" ?

Yes. int main(void) declares a function returning nothing and having
no parameters. int main() declares a function returning nothing and
having an unspecified number of parameters of unspecified types.
should be able to fix this if i can return an array.

There is no need to return an array. Return a pointer to the string
you've builded already is all you needs. The string should not be an
auto variable becauser that will get indertimine with the return
statement. But using either a static array, a malloced memory area
(the calle would be required to free() it) or extern or at file scope.


--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 
C

CBFalconer

Herbert said:
Yes. int main(void) declares a function returning nothing and having
no parameters. int main() declares a function returning nothing and
having an unspecified number of parameters of unspecified types.

Do try for some elementary accuracy. "int main(..." declares a
function returning an int, not nothing. This has always been so in
C. I recommend reading your own article before triggering 'send'.
 
B

Bill Pursell

Herbert said:
Yes. int main(void) declares a function returning nothing and having
no parameters. int main() declares a function returning nothing and
having an unspecified number of parameters of unspecified types.

int main(void) declares a function returning int. void foo(void)
declares a function named foo that takes no arguments and has no return
value. foo(void) implicitly declares a function which takes no
arguments and returns an int (failing to specify a return value is poor
practice and highly frowned upon.)
 
F

Flash Gordon

Herbert said:
Yes. int main(void) declares a function returning nothing and having
no parameters. int main() declares a function returning nothing and
having an unspecified number of parameters of unspecified types.

You mean returning an int, not returning nothing.
--
Flash Gordon, living in interesting times.
Web site - http://home.flash-gordon.me.uk/
comp.lang.c posting guidelines and intro:
http://clc-wiki.net/wiki/Intro_to_clc

Inviato da X-Privat.Org - Registrazione gratuita http://www.x-privat.org/join.php
 
B

ben.carbery

Ok, that does the trick.

I have now moved the program to a linux system which was a bit fussier.
I cleaned up a bit by removing any global vars and making proper use of
function returns.

The program is compiling ok but I receive this warning:

daysalive.c: In function `speakdate':
daysalive.c:92: warning: function returns address of local variable

Is this a problem? Relevant code below.

char *speakdate(int d, int m, int y)
{
<snip>
return datestring;
}

int main(void)
{
<snip>
printf ("Your date of birth is
%s\n\n",speakdate(bdate,bmonth,byear));
<snip>
printf ("The current date is:
%s\n\n",speakdate(cdate,cmonth,cyear));
<snip>
}
 
O

Old Wolf

The program is compiling ok but I receive this warning:

daysalive.c: In function `speakdate':
daysalive.c:92: warning: function returns address of local variable

Is this a problem? Relevant code below.

char *speakdate(int d, int m, int y)
{
<snip>
return datestring;
}

You snipped the relevant code :) I presume it was something like:
char datestring[80];

Assuming that to be the case: Yes it is a problem. datestring
ceases to exist when that function exits. So you end up
returning a pointer to something that no longer exists.

Simple solution is to make datestring have a permanent lifetime:
static char datestring[80];

Note that this means that all calls to speakdate() will use the
same buffer -- so don't try calling the function twice before you
go to use the results of the first call.
 
B

Ben

Ok that fixed it. So the reason it works anyway is that the variable
still lives in physical memory?
 
H

Herbert Rosenau

Do try for some elementary accuracy. "int main(..." declares a
function returning an int, not nothing. This has always been so in
C. I recommend reading your own article before triggering 'send'.

Sorry, I was a bit overtired yesterday evening, you're right.


--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 
D

Default User

Ben said:
Ok that fixed it. So the reason it works anyway is that the variable
still lives in physical memory?

Please review the information below.



Brian
 
O

Old Wolf

Ben said:
Ok that fixed it. So the reason it works anyway is that the variable
still lives in physical memory?

Please quote previous messages when posting -- some people
view this newsgroup in an interface that doesn't show post history.

If it "works anyway" it is probably because your pointer is still
pointing to where the object was , and nothing has happened
to re-use that memory yet. Note that this is off-topic for this
group, which ceases to care what happens once your program
violates the C standard, because it will behave differently on
different systems. If you want to investigate this issue further
then post on a newsgroup for your system (eg. a GCC group, or
comp.unix.programmer, or comp.os.ms-windows.programmer.win32).
 
P

Peter Shaggy Haywood

Groovy hepcat (e-mail address removed) was jivin' on 29 Apr 2006 23:52:57
-0700 in comp.lang.c.
First program in C - what is going on with function returns?'s a cool
scene! Dig it!
I have just written a simple program to get me started in C that
calculates the number of days since your birthdate.
One thing that confuses me about the program (even though it works) is
how global variables and function returns work...

Global variables are just objects that can be seen by every
function, so the value can be fetched by every function and the value
can be modified by every function; which is why it's a bad idea to use
them. You don't want some function accidentally modifying something it
shouldn't because of a typo or something.
Fuction return values are just the values that get passed back from
a called function to its caller.
For example, I have a global array "char datestring[80];" which is
defined in the function speakdate.

No you don't. If it's defined in speakdate() then it isn't a global
array. It's local to speakdate(). But datestring is indeed global,
defined at file scope, not within speakdate().
speakdate just converts a set of
integers (date variables) to a string.

The main program then does:
"printf ("The current date is:
%s\n\n",speakdate(cdate,cmonth,cyear));"

And correctly prints the value of datestring.
What I don't get is why this works since I haven't explicitly told
speakdate to return datestring.

This is happening by sheer (not necessarily good) luck! You are
invoking undefined behaviour, and that means that anything could
happen.
I figured by default it would return nothing at all.

speakdate() has a return type of int, but there's no return
statement. I'm surprised it even compiles. You must at least be
getting a diganostic message warning you of this situation.
Full code below. By the way any other tips on my code would be welcomed
and appreciated!

char datestring[80];
/* dim is 'days in month'*/
int dim;

speakdate(int d, int m, int y)

In C90 (the old version of the C standard) you could write a
function declaration like this, without specifying a return type, and
the return type defaults to int. In C99 (the newer version of the
standard), however, you can't do this. You must explicitly state the
return type of each function.
Since you seem to want to pass the return value of this function
directly to printf(), you should be returning a char * from this
function, like so:

char *speakdate(int d, int m, int y)

Or, better still, make it a const char *:

const char *speakdate(int d, int m, int y)
{

char stdate[5],stmonth[10],styear[5];

sprintf( stdate, "%d", d);
sprintf( styear, "%d", y);

Undefined behaviour, calling an undeclared variadic function. You've
not included any headers. Very, very bad!
switch (d) {
case 1 :
case 21 :
case 31 : strcat(stdate,"st ");
/*printf("The date is %s\n",stdate);*/
break;
case 2 :
case 22 : strcat(stdate,"nd ");
/*printf("The date is %s\n",stdate);*/
break;
case 3 :
case 23 : strcat(stdate,"rd ");
/*printf("The date is %s\n",stdate);*/
break;
case 4 :
case 5 :
case 6 :
case 7 :
case 8 :
case 9 :
case 10 :
case 11 :
case 12 :
case 13 :
case 14 :
case 15 :
case 16 :
case 17 :
case 18 :
case 19 :

You missed the 20th!
case 24 :
case 25 :
case 26 :
case 27 :
case 28 :
case 29 :
case 30 : strcat(stdate,"th ");
/*printf("The date is %s\n",stdate);*/
break;
default : strcat(stdate,"Invalid ");
/*printf("The date is %s\n",stdate);*/
break;
}

You're not going to check that the day is valid for the month? You
don't want to accept the 31st of Febuary, do you? So now would be a
good time to check for things like that. Return an error message or do
something else useful if he date is invalid. You've made sure the day
is between 1 and 31, but you've not checked for the number of days in
the month.
switch (m) {
case 1 : strcpy(stmonth,"January");
/*printf("The month is %s\n",stmonth);*/
break;
case 2 : strcpy(stmonth,"February");
/*printf("The month is %s\n",stmonth);*/
break;
case 3 : strcpy(stmonth,"March");
/*printf("The month is %s\n",stmonth);*/
break;
case 4 : strcpy(stmonth,"April");
/*printf("The month is %s\n",stmonth);*/
break;
case 5 : strcpy(stmonth,"May");
/*printf("The month is %s\n",stmonth);*/
break;
case 6 : strcpy(stmonth,"June");
/*printf("The month is %s\n",stmonth);*/
break;
case 7 : strcpy(stmonth,"July");
/*printf("The month is %s\n",stmonth);*/
break;
case 8 : strcpy(stmonth,"Aug");
/*printf("The month is %s\n",stmonth);*/
break;
case 9 : strcpy(stmonth,"Sep");
/*printf("The month is %s\n",stmonth);*/
break;
case 10 : strcpy(stmonth,"Oct");
/*printf("The month is %s\n",stmonth);*/
break;
case 11 : strcpy(stmonth,"Nov");
/*printf("The month is %s\n",stmonth);*/
break;
case 12 : strcpy(stmonth,"Dec");
/*printf("The month is %s\n",stmonth);*/
break;
default : strcpy(stmonth,"Invalid");
/*printf("The month is %s\n",stmonth);*/
break;
} /* end of switch */

strcpy(datestring,stdate);
strcat(datestring,stmonth);
strcat(datestring," ");
strcat(datestring,styear);
strcat(datestring,".");
/*printf("%s",datestring);*/

This is the place to return datestring, like so:

return datestring;
}

int countdays(int bd, int bm, int by, int cd, int cm, int cy)
{

int month,year;

int daysalive = 0;

/* count the days in whole years */
for (year=by+1;year<cy;year=++year) {
if (year==2000) {
daysalive = daysalive + 365;
/*printf("year is %d, adding 365, daysalive counted so
far is %d\n",year,daysalive);*/
}
else {
if (fmod(year,4)==0) {
daysalive = (daysalive + 366);
/*printf("year is %d, adding 366, daysalive counted
so far is %d\n",year,daysalive);*/
}
else {
daysalive = (daysalive + 365);
/*printf("year is %d, adding 365, daysalive counted
so far is %d\n",year,daysalive);*/
}
}
}

Your logic seems very shakey here. It's difficult to understand. It
seems to be wrong. For one thing, 2000 was a leap year. A year is a
leap year if

1) it is a multiple of 4 but
2) it is not a multiple of 100 unless
3) it is a multiple of 1000.

You need to simplify this section of code. What you need is a
function that can determine whether a year is a leap year. Then all
you do is this:

for(year = by + 1; year < cy; year++)
{
dayslive += 365;
if(leapyr(year))
{
dayslive++;
}
}

And leapyr() could be something like this:

int leapyr(int yr)
{
if(0 == (yr % 4) && 0 != (yr % 100) || 0 == (yr % 1000))
{
return 1;
}
else
{
return 0;
}
}
/*printf("%d\n",daysalive);*/

/* days in whole months this year */
for (month=cm-1;month>0;--month) {
daysalive = (daysalive + (monthswitch(month,year)));

The inner parentheses (the ones around the function call) are
superfluous. For that matter, so are the outer ones. This would have
sufficed:
daysalive = daysalive + monthswitch(month,year);
/*printf("adding %d, month is
%d\n",(monthswitch(month,year)),month);*/
}
/*printf("%d\n",daysalive);*/

/* days so far in the current month */
daysalive = (daysalive + cd);
/*printf("%d\n",daysalive);*/

/* days in whole months in birth year */
for (month=bm+1;month<13;++month) {
daysalive = (daysalive + (monthswitch(month,year)));
}
/*printf("%d\n",daysalive);*/

/* days in birth month */
daysalive = (daysalive + (monthswitch(bm,by)) - bd);
/*printf("%d\n",daysalive);*/

return daysalive;

The logic isn't immediately obvious, but the code's a mess, so I
won't bother trying to understand or debug it.
}

int monthswitch(int month,int year) {
switch (month) {
case 4 :
case 6 :
case 9 :
case 11 :
case 12 : dim = 30;
break;
case 1 :
case 3 :
case 5 :
case 7 :
case 8 :
case 10 : dim = 31;
break;
case 2 :
if (year==2000) {
dim = 28;
break;
}
if (fmod(year,4)==0) {
dim = 29;
break;
}
else
dim = 28;
break;
}
return dim;
}

main(void)

int main(void)

Even if you're using a C90 implementation, it's still a good idea to
specify the return type, rather than let it default to int.
{

int bdate,bmonth,byear;

printf ("Please enter your birth date (d/m/yyyy):\n");
scanf ("%d/%d/%d",&bdate,&bmonth,&byear);
printf ("Your date of birth is
%s\n\n",speakdate(bdate,bmonth,byear));

int cdate,cmonth,cyear;

In C90 you can't declare variables here. Variables declared at block
scope must be declared at the top of the innermost block in which they
are declared, before any executable statements. Now, either you are
using a C90 implementation, in which case you can't declare variables
here; or you are using a C99 implementation, in which case you can't
declare functions without an explicit return type. You are taking
advantage of extentions to the language. Don't do that. Write portable
code.
printf ("Please enter the current date (d/m/yyyy):\n");
scanf ("%d/%d/%d",&cdate,&cmonth,&cyear);
printf ("The current date is:
%s\n\n",speakdate(cdate,cmonth,cyear));

And speaking of portable code, this ain't it! Portable code doesn't
rely on undefined behaviour.
Of course, if you make the changes to speakdate() I suggested above,
then this becomes valid.
printf ("Congratulations! You were born a total of %d days
ago.\n",countdays(bdate,bmonth,byear,cdate,cmonth,cyear));

return 0;

Your code is badly formatted. This makes it hard to read and
understand. If you must put debug statements in your code, and then
comment them out, cut them out altogether before posting here. That
sort of thing adds to clutter, making code harder to read.
Some lines have wrapped in the middle of strings, making
copy-paste-compile attempts a pain. If you had included more white
space in some of those lines they would have wrapped at more
reasonable places. But you should endeavour to write code, especially
code you post here, that has lines no longer than about 70 characters.
It's a good idea to pre-wrap any lines longer than that, so they look
neat & tidy.

--

Dig the even newer still, yet more improved, sig!

http://alphalink.com.au/~phaywood/
"Ain't I'm a dog?" - Ronny Self, Ain't I'm a Dog, written by G. Sherry & W. Walker.
I know it's not "technically correct" English; but since when was rock & roll "technically correct"?
 
D

Dave Thompson

Hi,

I have just written a simple program to get me started in C that
calculates the number of days since your birthdate.

In addition to the other answers that have correctly pointed out:
- the return value from speakdate() is unspecified/indeterminate and
may happen to work by accident of some implementations
- year=++year is wrong, in fact Undefined Behavior which is the worst
kind of wrong and could theoretically do anything, although this
particular case in practice will probably do no worse than give a
wrong result. OTOH in several places where you have
daysalive = daysalive + someexpr
you could use daysalive += someexpr
- year is an integer so you can use % for remainder (technically not
modulus, which may be different for negative numbers)

I have the following additional comments:

Years evenly divisible by 400 like 2000 _are_ leap years but other
years evenly divisible by 100 like 1900 and 2100 are not. (If your
program is used only by people alive today, likely very very few of
them will have been born before 1901.)

And rather than having two different forms of logic for testing leap
years, I would suggest making that determination a function and use it
in both (or all) places. Or a macro, but that's a bit harder to get
right or debug, and you are a beginner, so stick with the simpler.

You don't need a switch and code for each possible month value, it's
easier to just have an array of names indexed by month number; and:

you don't need to generate each piece separately and then concatenate
them; this is a perfect application for sprintf, like:

static const char * monname [12] = {"January", "February", etc. }

sprintf (somewhere, "%d%s %s %d.", d, suffix(d), monname[m-1], y);
/* or if you haven't already dealt with invalid data, which */
/* you normally should do as close to the input as possible */
... m<1||m>12? "invalid": monname[m-1] ...

(Or even better in general snprintf if you have a C99 implementation,
or a C90 one that provides it as an extension. Although in this
particular case you can easily determine a safe buffer size.)

Why do you spell out January thru July but abbreviate Aug thru Dec?
It's usually best to be consistent unless there's a good reason.

It's also possible to simplify the suffix calculation some, but that
can get trickier, especially as I would be tempted to take advantage
of the fact that we are already decimalizing the day-number.

Depending on your platform, the maximum value of an 'int' variable may
be as little as 32767 (16 bits) which in days is a little less than 90
years, so some users of your program might reasonably exceed this.
'long' would be (much!) more than safe.

Rather than have the user enter the current date, you can* get the
current date-and-time from the standard C library in encoded form by
calling time(), and decode it by calling localtime(). But note that
the struct tm, obtained from localtime(), has month numbers starting
with 0 for Jan (not 1) and year numbers biased by 1900. (Not modulo
100 as some people thought, causing Y2K bugs!)

* Technically time() can return an error, but the only platforms where
it is likely to do so are ones where stdio probably won't work either,
making your whole program useless anyway.

In fact, you can use the standard library to do almost your whole job
for you by populating a struct tm with year month day and either an
actual hour minute second or arbitrary ones (all zero), and is_dst,
and calling mktime() to get a time_t; getting another time_t for the
current time from time(); and calling difftime() to take their
difference in seconds; and dividing by 86400 to give days.

- David.Thompson1 at worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top