Stroustrup 5.9 exercise 13 (creating a structure)

A

arnuld

problem: define a /struct Date/ to keep track of dates. provide
functions that read Dates from input, write Dates to output &
initialize a date with date.

solution: i thought of a /vector/ of /Date structures/. "Date" struct
carries 3 things: month, date & year. i wrote the following code & of
course it gives an error:


#include <iostream>
#include <string>
#include <vector>

struct Date {
std::string month;
int date;
int year;
};

std::vector<Date> vd;

void create_date(std::string m, int d, int y) {
Date da = {m, d, y};
vd.push_back(da);
}

void date_input(std::vector<Date> vdate) {
std::string month;
int date, year;

std::cout << "Enter Date (MM DAY YEAR): ";
std::cin >> month;
std::cin >> date;
std::cin >> year;

create_date(month, date, year);
}

void print_date(Date* vdate) {
std::cout << vdate->month << '\n'
<< vdate->date << '\n'
<< vdate->year << '\n';
}

void print_all_dates(std::vector<Date> vdate) {
for(std::vector<Date>::iterator iter=vdate.begin();
iter != vdate.end();
++iter)
{
print_date(*iter);
}
}


int main() {
date_input(vd);
}


--------- error -----------------------------------

05_ex-13.cpp: In function 'void print_all_dates(std::vector<Date,
std::allocator<Date> >)':
05_ex-13.cpp:44: error: cannot convert 'Date' to 'Date*' for
argument '1' to 'void print_date(Date*)'
 
B

benben

arnuld said:
problem: define a /struct Date/ to keep track of dates. provide
functions that read Dates from input, write Dates to output &
initialize a date with date.

solution: i thought of a /vector/ of /Date structures/. "Date" struct
carries 3 things: month, date & year. i wrote the following code & of
course it gives an error:


#include <iostream>
#include <string>
#include <vector>

struct Date {
std::string month;
int date;
int year;
};

std::vector<Date> vd;

void create_date(std::string m, int d, int y) {
Date da = {m, d, y};
vd.push_back(da);
}

void date_input(std::vector<Date> vdate) {

what is vdate for?
std::string month;
int date, year;

std::cout << "Enter Date (MM DAY YEAR): ";
std::cin >> month;
std::cin >> date;
std::cin >> year;

create_date(month, date, year);
}

void print_date(Date* vdate) {
std::cout << vdate->month << '\n'
<< vdate->date << '\n'
<< vdate->year << '\n';
}

void print_all_dates(std::vector<Date> vdate) {

You probably want

const std::vector<Date>& vdates

to avoid copying.
for(std::vector<Date>::iterator iter=vdate.begin();
iter != vdate.end();
++iter)
{
print_date(*iter);

You should have

print_date(&*iter);

to compile. iter is an iterator, first use operator * to obtain the
object it points to, then use operator & obtain a pointer to that
object, which print_date() requires.
}
}


int main() {
date_input(vd);
}


--------- error -----------------------------------

05_ex-13.cpp: In function 'void print_all_dates(std::vector<Date,
std::allocator<Date> >)':
05_ex-13.cpp:44: error: cannot convert 'Date' to 'Date*' for
argument '1' to 'void print_date(Date*)'

Learn to read error messages. It'll but a lot of help!
how can i run the desired programme?

Ben
 
V

VJ

arnuld said:
problem: define a /struct Date/ to keep track of dates. provide
functions that read Dates from input, write Dates to output &
initialize a date with date.

solution: i thought of a /vector/ of /Date structures/. "Date" struct
carries 3 things: month, date & year. i wrote the following code & of
course it gives an error:


#include <iostream>
#include <string>
#include <vector>

struct Date {
std::string month;
int date;
int year;
};

std::vector<Date> vd;

void create_date(std::string m, int d, int y) {
Date da = {m, d, y};
vd.push_back(da);
}

void date_input(std::vector<Date> vdate) {
std::string month;
int date, year;

std::cout << "Enter Date (MM DAY YEAR): ";
std::cin >> month;
std::cin >> date;
std::cin >> year;

create_date(month, date, year);
}

void print_date(Date* vdate) {
std::cout << vdate->month << '\n'
<< vdate->date << '\n'
<< vdate->year << '\n';
}

void print_all_dates(std::vector<Date> vdate) {
for(std::vector<Date>::iterator iter=vdate.begin();
iter != vdate.end();
++iter)
{
print_date(*iter); <------------------------------------
}
}


int main() {
date_input(vd);
}


--------- error -----------------------------------

05_ex-13.cpp: In function 'void print_all_dates(std::vector<Date,
std::allocator<Date> >)':
05_ex-13.cpp:44: error: cannot convert 'Date' to 'Date*' for
argument '1' to 'void print_date(Date*)'

marked line should be:
print_date( iter );
otherwise you would pass an object, instead of a pointer to the object
 
K

Keshav

arnuld said:
problem: define a /struct Date/ to keep track of dates. provide
functions that read Dates from input, write Dates to output &
initialize a date with date.

solution: i thought of a /vector/ of /Date structures/. "Date" struct
carries 3 things: month, date & year. i wrote the following code & of
course it gives an error:


#include <iostream>
#include <string>
#include <vector>

struct Date {
std::string month;
int date;
int year;
};

std::vector<Date> vd;

void create_date(std::string m, int d, int y) {
Date da = {m, d, y};
vd.push_back(da);
}

void date_input(std::vector<Date> vdate) {
std::string month;
int date, year;

std::cout << "Enter Date (MM DAY YEAR): ";
std::cin >> month;
std::cin >> date;
std::cin >> year;

create_date(month, date, year);
}

void print_date(Date* vdate) {
std::cout << vdate->month << '\n'
<< vdate->date << '\n'
<< vdate->year << '\n';
}

void print_all_dates(std::vector<Date> vdate) {
for(std::vector<Date>::iterator iter=vdate.begin();
iter != vdate.end();
++iter)
{
print_date(*iter);
}
}


int main() {
date_input(vd);
}


--------- error -----------------------------------

05_ex-13.cpp: In function 'void print_all_dates(std::vector<Date,
std::allocator<Date> >)':
05_ex-13.cpp:44: error: cannot convert 'Date' to 'Date*' for
argument '1' to 'void print_date(Date*)'
in calling function print_date u r using *iter which will give u Date
not Date* (Vector is of Date not Date *) so u can always use

Date date = *iter;
print_date(&date);
or
print_date(&(*iter));


-K2G
 
E

Earl Purple

arnuld said:
problem: define a /struct Date/ to keep track of dates. provide
functions that read Dates from input, write Dates to output &
initialize a date with date.

solution: i thought of a /vector/ of /Date structures/. "Date" struct
carries 3 things: month, date & year. i wrote the following code & of
course it gives an error:


#include <iostream>
#include <string>
#include <vector>

struct Date {
std::string month;
int date;
int year;
};

std::vector<Date> vd;

void create_date(std::string m, int d, int y) {
Date da = {m, d, y};
vd.push_back(da);
}

Any law against giving your struct a trivial constructor?

struct Date
{
std::string month;
int date;
int year;

Date() : month( "Jan"), date( 1 ), year ( 2000 ) {}

Date( const std::string & m, int d, int y )
: month ( m ), date( d ), year( y )
{
}
};

then:

vd.push_back( Date( m, d y ) );
void print_date(Date* vdate) {
std::cout << vdate->month << '\n'
<< vdate->date << '\n'
<< vdate->year << '\n';
}

Bad use of pointers for more than one reason. The user is never going
to pass in a NULL one (if they do it's UB). In addition your print
function isn't going to modify the date so use a const reference. There
is another big reason why you'll want your function to take a const
reference as you'll see below. Anyway

void print_date( const Date & vdate )
{
std::cout << vdate.month << '\n' << vdate.date << '\n' << vdate.year
<< '\n';
}

Of course we can do better than specify cout as the output source. The
best is simply to overload operator << for dates so

std::eek:stream & operator<<( std::eek:stream & os, const Date & vdate )
{
os << vdate.month << '\n' << vdate.date << '\n' << vdate.year <<
'\n';
return os;
}

void print_date( const Date & vdate )
{
std::cout << vdate;
}
void print_all_dates(std::vector<Date> vdate) {
for(std::vector<Date>::iterator iter=vdate.begin();
iter != vdate.end();
++iter)
{
print_date(*iter);
}
}

Once again you need to pass by const reference. Although vectors are
copyable it is best not to copy it but to pass it by const reference.

In addition, having now rewritten the print_date function to take a
const reference we can make use of the std::for_each algorithm. Thus:

void print_all_dates( const std::vector< Date > & vdates )
{
std::for_each( vdates.begin(), vdates.end(), print_date );
}

If you want to use operator<< then it's a bit more complex but
something you should get used to:

void print_all_dates( const std::vector< Date > & vdates )
{
std::copy
(
vdates.begin(), vdates.end(),
std::eek:stream_iterator< Date >( cout, "" ) // "" is a
delimiter
);
}

Of course you won't really need to write these functions at all because
their implementations are just one-liners so you use the one-liners
when you need to print them all anyway.

You will need to include headers <iterator> and <algorithm>
 
A

arnuld

benben said:
what is vdate for?

oops! i have removed it.
You probably want

const std::vector<Date>& vdates

to avoid copying.

yes, exactly, changed that too.
You should have

print_date(&*iter);

to compile. iter is an iterator, first use operator * to obtain the
object it points to, then use operator & obtain a pointer to that
object, which print_date() requires.

i changed it and it works but why /&/ works and /*/ gives an error. i
mean, you asked me to use "reference" to obtain a "pointer" and it
works but if i use "pointer" to obtain a "pointer" (i.e. **iter) i get
an error. why?
Learn to read error messages. It'll but a lot of help!

i think this will take experience which takes a lot of time & i am
investing my time into C++ :)
 
A

arnuld

Earl said:
Any law against giving your struct a trivial constructor?

i am a newbie to C++ so i dont know what are constructors.

Bad use of pointers for more than one reason. The user is never going
to pass in a NULL one (if they do it's UB).

what does this mean?
In addition your print
function isn't going to modify the date so use a const reference. There
is another big reason why you'll want your function to take a const
reference as you'll see below. Anyway

that is a good reason & was my intention. i tried it before but it
raises an error.
Of course we can do better than specify cout as the output source. The
best is simply to overload operator << for dates so

std::eek:stream & operator<<( std::eek:stream & os, const Date & vdate )
{
os << vdate.month << '\n' << vdate.date << '\n' << vdate.year <<
'\n';
return os;
}

out of my head.

Once again you need to pass by const reference. Although vectors are
copyable it is best not to copy it but to pass it by const reference.

yes, Stroustrup does this most of the time. someone at my previous
other thread pointed this thing to me with C++ FAQs on "const
correctness". i understand it.
In addition, having now rewritten the print_date function to take a
const reference we can make use of the std::for_each algorithm. Thus:

void print_all_dates( const std::vector< Date > & vdates )
{
std::for_each( vdates.begin(), vdates.end(), print_date );
}

good. i will do this.
If you want to use operator<< then it's a bit more complex but
something you should get used to:

void print_all_dates( const std::vector< Date > & vdates )
{
std::copy
(
vdates.begin(), vdates.end(),
std::eek:stream_iterator< Date >( cout, "" ) // "" is a
delimiter
);
}

out of my head.
Of course you won't really need to write these functions at all because
their implementations are just one-liners so you use the one-liners
when you need to print them all anyway.

You will need to include headers <iterator> and <algorithm>

that is fine & i will use them in future when i will be able to
understand them & that will happen when Stroustrup will explain.

thanks a lot.
 
E

Earl Purple

arnuld said:
i am a newbie to C++ so i dont know what are constructors.

I know that Stroustrup doesn't believe in teaching C first so I don't
get why he hasn't yet taught using constructors.

Anyway, in its simplest form, a constructor is a simple function. Now
maybe he has taught you that in C++ structs and classes are the same
and that they can have member functions that access their member
variables. The constructor is the first function that is called when
you create an instance of a struct or class - it is only called at this
time and cannot be subsequently called later. It has the form that I
have shown you and in its simplest form is used to initialise the class
members.
what does this mean?

It means "undefined behaviour", which is what happens in C++ when you
do something illegal. It will often cause your program to crash but is
not guaranteed to do so, and it may work at first then crash or err
later on.
that is a good reason & was my intention. i tried it before but it raises an error.

Probably because you did it wrong. Did you use -> syntax? With a
reference you use . syntax.
out of my head.

ostream is a generic stream. The above writes the data of your class in
text format into any stream but it doesn't specify what type of stream
it is. It could be to the console, it might be to a file or it might be
to memory.
good. i will do this.

This is the simplest form of an algorithm .It is clear this is not
above your head so perhaps you can start to think along these lines.

When you want print_date to take extra parameters then you can learn to
write a simple functor.
out of my head.

Yes, probably would be if std::eek:stream is, as we've taken this to a
higher level of complexity.
std::copy is a generic algorithm that takes a sequence and writes it to
another location. You've come across iterators: they use operator* and
operator ++ just like pointers do, except that they are more generic
than a pointer, i.e. a pointer is a special type of iterator.
Algorithms make use of the fact that iterators use operator++ and
operator*. operator* normally returns a reference to something. Now
references can be const (read-only) or non-const. copy requires a
non-const reference because it is going to write to it using
assignment (operator=).

However it doesn't have to be a reference at all. It can be an instance
of a class that wraps a reference. It can even be the iterator itself.
In fact ostream_iterator is a cheat with regards to operator++ as it
doesn't change anything at all - it always writes to the end of the
stream. It is also a cheat with regards to operator* which also returns
itself. All the work is done in operator= which simply writes the
object to the stream.

Note that back_inserter is another example of an iterator that
"cheats".
that is fine & i will use them in future when i will be able to
understand them & that will happen when Stroustrup will explain.

I'm sure he will. If not, then read Scott Meyers' "Effective STL". It
was that book that converted me to using them.
 
M

Marcus Kwok

arnuld said:
i changed it and it works but why /&/ works and /*/ gives an error. i
mean, you asked me to use "reference" to obtain a "pointer" and it
works but if i use "pointer" to obtain a "pointer" (i.e. **iter) i get
an error. why?

The meaning of '&' and '*' changes depending on the context.

For example:
int* p = new int(42); // * means that p is a pointer to int
int i = *p; // * means to dereference the pointer p
int j = i * i; // * means to multiply i by i

int& r = i; // & means that r is a reference to i;
int* p2 = &i; // & means to take the address of i
int a = i & i; // & means to do bitwise-and operation
 
B

BobR

arnuld wrote in message ...
i changed it and it works but why /&/ works and /*/ gives an error. i
mean, you asked me to use "reference" to obtain a "pointer" and it
works but if i use "pointer" to obtain a "pointer" (i.e. **iter) i get
an error. why?

Another way to write **iter is *iter[]. So, then you would be trying to pass
an array of pointers (loosely speaking).

(&) take the address of (*iter) the object the iter is pointing to.
 

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

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top