Sign in to follow this  

dynamically allocated array of structures

This topic is 2667 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a question about another program exercise in C++ Primer Plus. I am at the end of chapter 4 and one of the problems says to write a program that creates an array of three structures, initializes them and then prints the contents of each. I complete that exercise without any problems but now the last exercise is asking the reader to go back to this program and allocate the array dynamically.

When dynamically allocating an array of structures can I still somehow initialize them as before with code something like this?
	candybar snack[3] =
{
{"Mocha", 2.3, 250},
{"Twist", 4.8, 125},
{"Toffee", 8.2, 65}
};



I Googled it and apparently someone else had the same problem with this exercise and came up with this solution but the code is so much longer that before and I was wondering if this is the shortest way to accomplish this.
#include <iostream>
using namespace std;

int main()
{
struct CandyBar //struct declaration
{
char *brand;
float weight;
int calories;
};

//dynamic array declaration
CandyBar *Candies = new CandyBar[3];
CandyBar *CandyPointer = &Candies[0]; //pointer to a CanyBar data object

//structure initialization one by one
(*CandyPointer).brand = "Mocha Munch";
CandyPointer->weight = 2.3;
CandyPointer->calories = 350;

CandyPointer = &Candies[1];
(*CandyPointer).brand = "Chilly Willy";
CandyPointer->weight = 2.2;
CandyPointer->calories = 200;

CandyPointer = &Candies[2];
(*CandyPointer).brand = "Lemon Rush";
CandyPointer->weight = 2.1;
CandyPointer->calories = 200;

//data output to the screen

//first element of the array
CandyPointer = &Candies[0];
cout << "Name of Candy Bar: " << (*CandyPointer).brand << endl;
cout << "Weight of Candy Bar: " << CandyPointer->weight << endl;
cout << "Number of calories in Candy Bar: " << CandyPointer->calories << "\n\n";

//second element of the array
CandyPointer = &Candies[1];
cout << "Name of Candy Bar: " << (*CandyPointer).brand << endl;
cout << "Weight of Candy Bar: " << CandyPointer->weight << endl;
cout << "Number of calories in Candy Bar: " << CandyPointer->calories << "\n\n";

//third element of the array
CandyPointer = &Candies[2];
cout << "Name of Candy Bar: " << (*CandyPointer).brand << endl;
cout << "Weight of Candy Bar: " << CandyPointer->weight << endl;
cout << "Number of calories in Candy Bar: " << CandyPointer->calories << "\n\n";

cin.get();
return 0;
}


Is this the shortest solution to this problem?

Thanks in advance

Share this post


Link to post
Share on other sites
You could do something like this :

int main(){
CandyBar *threeCandyBars = new CandyBar[3];
{
CandyBar threeBars[3] = { /*initialize the 3 bars like you did first */ }
threeCandyBars[0] = threeBars[0];
threeCandyBars[1] = threeBars[1];
threeCandyBars[2] = threeBars[2];
//or std::copy(threeBars,threeBars+3,threeCandyBars);
}
}

Share this post


Link to post
Share on other sites
Since you are learning C++, I'm going to re-write that for you in C++. I don't have the book, so this probably skips over some stuff, but it gets you straight to some of the safer code to be writing.


#include <iostream> // cout
#include <string> // std::string
#include <vector> // std::vector

//struct declaration
struct CandyBar
{
std::string brand; // This is c++, use a std::string instead of a char *
float weight;
int calories;

CandyBar( const std::string &brand, float weight, int calories ) : // class constructor! they work on structs too
brand(brand), // This format is called an "initalizer list", and lets you efficiently set
weight(weight), // the members of a class.
calories(calories)
{}
};


int main()
{
// dynamic array declaration
// A std::vector< Type > acts almost exactly like a "Type array[5]" or "Type *array = new Type[5]"
// but is the C++ way to do things, since it is dynamic, type safe, and handles the memory management for you.
std::vector< CandyBar > Candies;

//structure initialization one by one

// We know we are adding 3 items, we should reserve space for them.
// When you know ahead of time you are going to add a lot of items, you should
// call reserve before adding them. (usually you'd do Candies.reserve( Candies.size() + items_to_add );
// YOU DON'T HAVE to call this here. It works fine without it.
Candies.reserve(3);

// push_back lets you add something to the end of the array. If you hadn't reserved space,
// this will reserve space for you.
// We use the constructor for CandyBar from above to initalize the candy bar data to add to the array.
Candies.push_back( CandyBar( "Mocha Munch", 2.3, 350 ) );
Candies.push_back( CandyBar( "Chilly Willy", 2.2, 200 ) );
Candies.push_back( CandyBar( "Lemon Rush", 2.1, 200 ) );

//data output to the screen
//We use an iterator to loop over the items in the array
for( std::vector< CandyBar >::iterator i = Candies.begin(); i != Candies.end(); ++i )
{
std::cout << "Name of Candy Bar: " << i->brand << std::endl;
std::cout << "Weight of Candy Bar: " << i->weight << std::endl;
std::cout << "Number of calories in Candy Bar: " << i->calories << std::endl << std::endl;
}

//We could just as easily use a number
//std::vector<T>::size() returns the number of used items in the array
//std::vector<T>::capacity() returns the number of slots in the array, counting both used and unused items.
for( std::vector< CandyBar >::size_type i = 0; i < Candies.size(); ++i )
{
std::cout << "Name of Candy Bar: " << Candies[i].brand << std::endl;
std::cout << "Weight of Candy Bar: " << Candies[i].weight << std::endl;
std::cout << "Number of calories in Candy Bar: " << Candies[i].calories << std::endl << std::endl;
}

// This isn't really needed.
// You're only using this here because you didn't explicitly call this from the commandline.
// Some debuggers will automatically add this when you launch in debug mode... some won't.
// Just remember you might not actually want this one in there later.
std::cin.get();

return 0;
}



Reference for you: std::string, std::vector.

There are a lot of other things you can do to make the code a bit better as well, but those are more advanced. You can use for_each instead of some loops, and overload operator << for you structure, so you could just do std::cout << Candies[0] << std::endl; and it would print the same stuff.

Share this post


Link to post
Share on other sites
Thanks for the help. I went with the first option just because it used methods that I have learned so far in the book. I really appreciated your recommendations for the second version for exposing me to better options with the language. I just have to wait until I can understand them better. :P

With that said, here is the program now and I have a question about it also.
#include <iostream>
#include <string>

struct candybar
{
std::string name;
float weight;
int cals;
};

int main()
{
using namespace std;
candybar * p_snack = new candybar[3];

candybar snack[3] =
{
{"Mocha", 2.3, 250},
{"Twist", 4.8, 125},
{"Toffee", 8.2, 65}
};
p_snack[0] = snack[0];
p_snack[1] = snack[1];
p_snack[2] = snack[2];

cout << "1st candybar: " << p_snack[0].name << ", " << p_snack[0].weight << ", " << p_snack[0].cals << endl;
cout << "2nd candybar: " << p_snack[1].name << ", " << p_snack[1].weight << ", " << p_snack[1].cals << endl;
cout << "3rd candybar: " << p_snack[2].name << ", " << p_snack[2].weight << ", " << p_snack[2].cals << endl;


cin.get();
return 0;
}



I will be honest and say that I didnt expect that to compile because I thought that we had to use the (->) operator when we used the "new" keyword for declaring memory. This is what my book says:

"The tricky part is accessing members. When you create a dynamic structure, you can’t use the dot membership operator with the structure name because the structure has no name. All you have is its address. C++ provides an operator just for this situation: the arrow membership operator (->)."

Do this not apply because I am still dealing with an array and need to use the dot operator to access individual elements of the array?

Thanks again!

Share this post


Link to post
Share on other sites
Quote:
Original post by Planemo
Do this not apply because I am still dealing with an array and need to use the dot operator to access individual elements of the array?


Winner!

p_snack is a pointer to an array of three snacks, therefore p_snack[0], p_snack[1] and p_snack[2] are the snack objects themselves.


p_snack[0] = snack[0];



is essentially


p_snack[0].name = snack[0].name;
p_snack[0].weight = snack[0].weight;
p_snack[0].calories = snack[0].calories;



if we take a pointer to the first snack instead, we would do this:


p_snack* snackPtr = &p_snack[0];
snackPtr->name = snack[0].name;
snackPtr->weight = snack[0].weight;
snackPtr->calories = snack[0].calories;


Share this post


Link to post
Share on other sites
OK thanks for the help everyone and I really appreciate it. I have decided to reread the chapter because its just too much information for me to rush through. I understood it all reading through and doing the exercises but now everything is starting to run together on me.

Thanks again

Share this post


Link to post
Share on other sites

This topic is 2667 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this