Stroustrup 5.9, exercise 7 (using struct)

A

arnuld

this one was much easier and works fine. as usual, i put code here for
any further comments/views/advice:

--------- PROGRAMME ------------
/* Stroustrup: 5.9 exercise 7

STATEMENTS:
Define a table of the name sof months o fyear and the number of days
in each month. write out that table. Do this twice:

1.) using ar array of char for names of months and an array of numbers
for number of days.

2.) using an array of structures. each structure holds the name of the
month
and its corresponding number of days.

here i used (2) option

*/


#include<iostream>

int main()
{
struct duo {
const char* month;
int days;
};

duo JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC;
JAN.month = "JAN";
FEB.month = "FEB";
MAR.month = "MAR";
APR.month = "APR";
MAY.month = "MAY";
JUN.month = "JUN";
JUL.month = "JUL";
AUG.month = "AUG";
SEP.month = "SEP";
OCT.month = "OCT";
NOV.month = "NOV";
DEC.month = "DEC";

JAN.days = 31;
FEB.days = 28;
MAR.days = 31;
APR.days = 30;
MAY.days = 31;
JUN.days = 30;
JUL.days = 31;
AUG.days = 31;
SEP.days = 30;
OCT.days = 31;
NOV.days = 30;
DEC.days = 31;

const int arr_size = 12;
duo arr[] = {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP};


duo* pduo = arr;

std::cout << "\tMONTH\tDays\n";
for(int i = 0; i < arr_size; ++i)
{
std::cout << '\t'
<< pduo->month
<< '\t'
<< pduo->days
<< std::endl;
++pduo;
}

return 0;
}
--------- OUTPUT -------------
[arch@voodo tc++pl]$ g++ -ansi -pedantic -Wall -Wextra 5.9_ex-07-
struct.cpp
[arch@voodo tc++pl]$ ./a.out
MONTH Days
JAN 31
FEB 28
MAR 31
APR 30
MAY 31
JUN 30
JUL 31
AUG 31
SEP 30
DEC 31
NOV 30
OCT 31
[arch@voodo tc++pl]$
 
A

Anand Hariharan

arnuld said:
this one was much easier and works fine. as usual, i put code here for
any further comments/views/advice:
(...)
struct duo {
const char* month;
int days;
};

duo JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC;

Avoid identifiers with all upper-case letters. All upper-case tends to
connote "screaming" or attracting attention, and you want to do that
only when necessary (you don't cry wolf all the time, do you?).


(...)
const int arr_size = 12;
duo arr[] = {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP};

Oops! arr does not have 12 elements. For this reason, it is best you
let the compiler evaluate this for you.

You have already used arr[] in the above definition. The compiler
determines its size. Likewise you say

const size_t arr_size = sizeof arr / sizeof *arr;
duo* pduo = arr;

std::cout << "\tMONTH\tDays\n";
for(int i = 0; i < arr_size; ++i)

If you define arr_size like I have done above, you should define i also
as size_t. Also, you were unlucky that your program did not noisily
fail for iterating beyond i=8 (but you did note that your output showed
DEC, NOV and OCT after SEP, didn't you?)
{
std::cout << '\t'
<< pduo->month
<< '\t'
<< pduo->days
<< std::endl;
++pduo;
}

Like Alf suggested elsewhere when responding to one of your posts, using
the subscript notation is more typical when iterating arrays.

- Anand
 
J

James Kanze

arnuld wrote:
const int arr_size = 12;
duo arr[] = {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP};
Oops! arr does not have 12 elements. For this reason, it is best you
let the compiler evaluate this for you.
You have already used arr[] in the above definition. The compiler
determines its size. Likewise you say
const size_t arr_size = sizeof arr / sizeof *arr;

That's more or less what you say in C (except as a macro, not as
a const variable). But it's error prone (suppose arr is the
parameter of a function). In C++, I've generally seen:

arr_size = size( arr ) ;

where size is defined:

template< typename T, size_t N >
size_t
size( T (&array)[ N ] )
{
return N ;
}

And I know, this is way beyond the level of the original
poster. But in his case, he really does want 12 entries: you
don't want the compiler determining the number of months in a
year, in some arbitrary fashion. So I'd make two changes:

-- arr_size is a ridiculous name; it doesn't tell us anything.
Something like:

int const monthsInYear = 12 ;

is far better.

-- You want to explicitly specify the size of the array:

MonthInfo monthInfo[ monthsInYear ] = { /*...*/ } ;

If you accidentaly give too many names (e.g. because you
duplicated one), the compiler will tell you. If you
accidentally give too few, I think some compilers will warn
as well; at least, you'll get a recognizable value (a null
pointer) rather than random garbage.
If you define arr_size like I have done above, you should define i also
as size_t.

You should really tell him why, as well:). The type of your
expression is size_t (although you could have declared it int);
size_t is an unsigned type, and mixing unsigned and signed types
in C++ can sometimes lead to surprising results.

Until you really know what you are doing, I'd recommend sticking
with int. All of the time, for everything. For that matter, I
only use unsigned types in a few, very special cases:

-- raw memory is unsigned char,

-- when the values a bit masks, etc., and I'm &'ing and |'ing,
rather than +'ing and -'ing, and

-- when a third party interface is using unsigned---as I say,
mixing the two can give surprising results, and should be
avoided.
Also, you were unlucky that your program did not noisily
fail for iterating beyond i=8 (but you did note that your output showed
DEC, NOV and OCT after SEP, didn't you?)

Right. The advantage of explicitly declaring the length of the
array is that it would have noisily failed (at least on most
general purpose systems).
Like Alf suggested elsewhere when responding to one of your posts, using
the subscript notation is more typical when iterating arrays.

Was more typical. I have the impression today that everyone
uses iterators, for everything. (And a pointer is an iterator.)
So you'd get something like:

for (char const** p = begin( monthNames ) ;
p != end( monthNames ) ;
++ p ) {
std::cout << '\t' << p->name << '\t' << p->days << std::endl ;
}

(with begin and end defined along the lines of size(), above).

Of course, I'm not saying that this is necessarily a positive
evolution:).
 
J

James Kanze

this one was much easier and works fine. as usual, i put code here for
any further comments/views/advice:
--------- PROGRAMME ------------
/* Stroustrup: 5.9 exercise 7
STATEMENTS:
Define a table of the name sof months o fyear and the number of days
in each month. write out that table. Do this twice:
1.) using ar array of char for names of months and an array of numbers
for number of days.
2.) using an array of structures. each structure holds the name of the
month
and its corresponding number of days.
here i used (2) option


int main()
{
struct duo {
const char* month;
int days;
};

You really need to work on your naming convention:

struct MonthInfo
{
char const* name ;
int dayCount ;
} ;

(Whether you use MonthInfo, month_info, Month_info, or whatever
is irrelevant, of course. But the name should indicate the
semantics of the type.)
duo JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC;
JAN.month = "JAN";
FEB.month = "FEB";
MAR.month = "MAR";
APR.month = "APR";
MAY.month = "MAY";
JUN.month = "JUN";
JUL.month = "JUL";
AUG.month = "AUG";
SEP.month = "SEP";
OCT.month = "OCT";
NOV.month = "NOV";
DEC.month = "DEC";
JAN.days = 31;
FEB.days = 28;
MAR.days = 31;
APR.days = 30;
MAY.days = 31;
JUN.days = 30;
JUL.days = 31;
AUG.days = 31;
SEP.days = 30;
OCT.days = 31;
NOV.days = 30;
DEC.days = 31;
const int arr_size = 12;
duo arr[] = {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP};

This is interesting. As an old C hacker (and seeing C style
arrays), my first reaction was that this shouldn't even compile.
But of course, it does, in C++. Still, I'd expect agglomerate
initialization:

int const monthsInYear = 12 ;
MonthInfo monthInfo[ monthsInYear ] =
{
{ "JAN", 31 },
{ "FEB", 28 },
{ "MAR", 31 },
// ...
} ;

Being able to do such initialization is, after all, the main
reason for using C style structs to begin with.
duo* pduo = arr;
std::cout << "\tMONTH\tDays\n";
for(int i = 0; i < arr_size; ++i)
{
std::cout << '\t'
<< pduo->month
<< '\t'
<< pduo->days
<< std::endl;
++pduo;
}

You can index, or you can use pointers, but there's no sense in
doing both:

for ( int i = 0 ; i < monthsInYear ; ++ i ) {
std::cout << '\t' << monthInfo[ i ].name
<< '\t' << monthInfo[ i ].dayCount
<< std::endl ;
}

If you want to be "in", of course, you'll use pointers, and some
template functions to get the start and end pointers, and write
something like:

for ( MonthInfo* iter = begin( monthInfo ) ;
iter != end( monthInfo ) ;
++ iter ) {
std::cout << '\t' << iter->name
<< '\t' << iter->dayCount
<< std::endl ;
}

IMHO, it's better to learn C++ thoroughly first, and then worry
about being "in":).
 
A

Anand Hariharan

IMHO, it's better to learn C++ thoroughly first, and then worry
about being "in":).

Learning C++ - a lifetime.
Learning it thoroughly - is it even possible?
Being "in" - priceless!
:)

Thanks for your critique of my other post, James.

sincerely,
- Anand
 
A

arnuld

On Apr 1, 8:01 pm, "arnuld" <[email protected]> wrote:
You really need to work on your naming convention:

struct MonthInfo
{
char const* name ;
int dayCount ;
} ;

(Whether you use MonthInfo, month_info, Month_info, or whatever
is irrelevant, of course. But the name should indicate the
semantics of the type.)

OK, 1st improvement i will do is "naming convention"

:)



This is interesting. As an old C hacker (and seeing C style
arrays), my first reaction was that this shouldn't even compile.
But of course, it does, in C++. Still, I'd expect agglomerate
initialization:

that was my typing mistake. i just forgot to put "OCT, NOV and DEC"

int const monthsInYear = 12 ;
MonthInfo monthInfo[ monthsInYear ] =
{
{ "JAN", 31 },
{ "FEB", 28 },
{ "MAR", 31 },
// ...
} ;

Being able to do such initialization is, after all, the main
reason for using C style structs to begin with.

Stroustrup said *specifically* that one must use a "struct" which nees
to contain the name and number of days of a month. that is why i used
a "struct" rather than "an array of arrays".


You can index, or you can use pointers, but there's no sense in
doing both:

ok, fine. with "arrays" i will use pointers, no indexing. i use
indexing with "vecotrs".

for ( MonthInfo* iter = begin( monthInfo ) ;
iter != end( monthInfo ) ;
++ iter ) {
std::cout << '\t' << iter->name
<< '\t' << iter->dayCount
<< std::endl ;
}

i did that and it does not even compile. see the FULL-code down here.

IMHO, it's better to learn C++ thoroughly first, and then worry
about being "in":).

i am not learning the "in". i am learning from Stroustrup's book and
he teaches like that. (BTW, i like his "style of teaching C++" )

--------- PROGRAMME ------------
/* Stroustrup: 5.9 exercise 7

STATEMENTS:
Define a table of the name sof months o fyear and the number of days
in each month. write out that table. Do this twice:

1.) using ar array of char for names of months and an array of numbers
for number of days.

2.) using an array of structures. each structure holds the name of the
month
and its corresponding number of days.

here i used (2) option

*/


#include<iostream>

int main()
{
struct MonthInfo {
const char* month;
int days;
};

MonthInfo JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV,
DEC;

JAN.month = "JAN";
FEB.month = "FEB";
MAR.month = "MAR";
APR.month = "APR";
MAY.month = "MAY";
JUN.month = "JUN";
JUL.month = "JUL";
AUG.month = "AUG";
SEP.month = "SEP";
OCT.month = "OCT";
NOV.month = "NOV";
DEC.month = "DEC";

JAN.days = 31;
FEB.days = 28;
MAR.days = 31;
APR.days = 30;
MAY.days = 31;
JUN.days = 30;
JUL.days = 31;
AUG.days = 31;
SEP.days = 30;
OCT.days = 31;
NOV.days = 30;
DEC.days = 31;

const int MonthsInYear = 12;
MonthInfo Months[MonthsInYear] = {JAN, FEB, MAR, APR, MAY, JUN, JUL,
AUG, SEP, OCT, NOV, DEC};


std::cout << "\tMONTH\tDays\n";

for(MonthInfo* iter = begin(Months); iter != end(Months); ++ iter)
std::cout << '\t'
<< iter->month
<<'\t'
<< iter->days
<< std::endl;


// for(int i = 0; i < MonthsInYear; ++i, ++PMonthInfo)
// {
// std::cout << '\t'
// << PMonthInfo->month
// << '\t'
// << PMonthInfo->days
// << std::endl;
// }

return 0;
}
---------- OUTPUT ------------
[arch@voodo tc++pl]$ g++ -ansi -pedantic -Wall -Wextra -O 5.9_ex-07-
struct.cpp
5.9_ex-07-struct.cpp: In function 'int main()':
5.9_ex-07-struct.cpp:61: error: 'begin' was not declared in this scope
5.9_ex-07-struct.cpp:61: error: 'end' was not declared in this scope
[arch@voodo tc++pl]$
 
J

James Kanze

On Apr 2, 12:41 pm, "James Kanze" <[email protected]> wrote:

[...]
that was my typing mistake. i just forgot to put "OCT, NOV and DEC"

That wasn't the problem I was thinking of. Omitting
initializers won't cause a error when compiling. Especially if
you haven't specified the size of the array. On the other hand,
C didn't (and maybe still doesn't) allow initializing an array
with a non-constant expression, and variables (even declared
const) are not constantes in C.
int const monthsInYear = 12 ;
MonthInfo monthInfo[ monthsInYear ] =
{
{ "JAN", 31 },
{ "FEB", 28 },
{ "MAR", 31 },
// ...
} ;
Being able to do such initialization is, after all, the main
reason for using C style structs to begin with.
Stroustrup said *specifically* that one must use a "struct" which nees
to contain the name and number of days of a month. that is why i used
a "struct" rather than "an array of arrays".

Where do you see an array of arrays? I'm using the definition
of MonthInfo above.

Also, if these definitions were in main (and not at global
scope), I'd probably declare the variables "static". It may be
preliminary for you, but the distinction between static
initialization and dynamic initialization can be very important
at times, and it makes sense to prefer static initialization
whenever possible.
ok, fine. with "arrays" i will use pointers, no indexing. i use
indexing with "vecotrs".

Hmmm. I'd almost expect the opposite:). Except with
iterators, instead of pointers, for std::vector.
i did that and it does not even compile. see the FULL-code down here.

That's probably because you don't have the definitions for begin
and end:).

As I said, it's the "in" solution; the solution you might prefer
if you wanted to show off a little bit. (There are cases where
it is appropriate, of course, but if you're still learning the
basics, as it would appear, just forget about it.)
i am not learning the "in". i am learning from Stroustrup's book and
he teaches like that. (BTW, i like his "style of teaching C++" )

I don't think you caught the meaning of "in". It was meant to
be somewhat ironic: "in fashion", or the latest mode. It is
currently very "in" to use complicated templates to solve the
simplest problems.

I'm sorry if this confused you. It wasn't meant to be a serious
suggestion, at least not in your case.
 

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,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top