Hi all
I'm trying to create a dynamic array of structures and have come across the following code but I can't figure out how some of it works: (incidentally this is from Prata's book C++ Primer Plus, Ch4, Ex.9)

#include <iostream>
using namespace std;

int main()
{
     //structure declaration
     struct CandyBar 
     {
     char brand[20];
     float weight;
     int calories;
     };

     //dynamic array declaration
     CandyBar *Candies = new CandyBar[3];

     //create pointer to the first CandyBar structure within the array
     CandyBar *CandyPointer = &Candies[0]; 

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

     <snipped code>

     return 0;
}

As far as I can understand - line 15

CandyBar *Candies = new CandyBar[3];

creates a pointer (Candies) which contains the address of the first element in the array (which in this case is a structure of CandyBar type)

line 18

CandyBar *CandyPointer = &Candies[0];

creates a pointer (CandyPointer) which points to the address of the previous pointer when it's pointing at the first element.

Why do we need this second pointer to initialise the array elements, rather than using the first pointer?
e.g.

CandyBar *Candies = new CandyBar[3];
Candies[0] = {"Violent Crumple", 20.5, 7000};

which I know doesn't work (syntax error) - but why not??

Thanks a lot
cobberas

when we do

CandyBar *Candies = new CandyBar[3];

we are allocating memory to hold 3 elements of CandyBar type and returning the pointer to the base address of this memory. This address will actually be same as the address of the 0th element.

both CandyPointer abd Candies point the same memory location. however for better understanding he has assigned the address of the 0th element to CandyPointer. also if he were to put this in a for loop and access each element of the array then he can use the same pointer and not lose the base address.

most importantly in C++ arrays, index starts from 0. That is the 1st element is Candies [0]

The pointer is not needed. Perhaps this code is simply a means to demonstrate how you might access the data either via its array element or a pointer to an element. For example, lines 21-23 might also be written as:

strcpy( Candies[0].brand , "Mocha Munch" ); //see below
     Candies[0].weight = 2.3;
     Candies[0].calories = 350;

Do you want to iterate a pointer or an index variable? You've got options.

And while we're at it, line 21 as originally written doesn't work, you can't use the assignment operator to copy to the C-style string.

Candies[0] = {"Violent Crumple", 20.5, 7000};

which I know doesn't work (syntax error) - but why not??

I think this will be possible in the next version of C++

That's great - thanks heaps.

both CandyPointer abd Candies point the same memory location

That's what I thought; glad I undersdtood this correctly!

if he were to put this in a for loop and access each element of the array then he can use the same pointer and not lose the base address.

OK. Good point; I hadn't thought of that - I'm not up to that chapter of the book yet :-)

Do you want to iterate a pointer or an index variable?

The latter, as you've shown in your sample code - thanks for that, it's exactly what I was trying to do (don't you just love novice programmers?!!)

I guess if I was wanting to access the array elements without losing the base address I'd iterate a pointer to the array rather than an index variable.

line 21 as originally written doesn't work, you can't use the assignment operator to copy to the C-style string.

Quite so - thanks!

Cheers
Cobberas

>>I think this will be possible in the next version of C++
You can do that now

struct CandyBar 
{
public:
    CandyBar (const char* brnd, float wt, int calors)
            : brand(brnd), weight(wt), calories(calors)
    {
    }
     string brand;
     float weight;
     int calories;
};

int main()
{
    CandyBar Bars("Violent Crumple", 20.5, 7000);
}

Apparently you can't make Bars and array, such as Bars[3] and use initialization lists like the above. Tried it but the compiler didn't like it.

For any other newbies out there having trouble with this exercise from Stephen Prata's book (and I've seen a few queries about this one on the 'net), here's the final solution I came up with:

//-------------------------------------------------------------------------
// Programming Exercise 4.9
//-------------------------------------------------------------------------

// PREPROCESSOR directive to include contents of the iostream & string files
#include <iostream>
#include <string>

struct CandyBar
{
	std::string brand;
	float weight;
	int calories;
};

int main(int argc, char* argv[])
{
	// make definitions made in the std namespace visible to the program
	using namespace std;

	//create a dynamic array of structures, & assign its address to a pointer
	//called 'ptrBar'
	//NB: ptrBar points to the 1st element of the array
	CandyBar * ptrBar = new CandyBar[3];

	//initialise the 3 arrays using the ptrBar pointer
	ptrBar[0].brand = "Mocha Munch";
	ptrBar[0].weight = 2.3;
	ptrBar[0].calories = 350;

	ptrBar[1].brand = "Violent Crumple";
	ptrBar[1].weight = 1.5;
	ptrBar[1].calories = 650;

	ptrBar[2].brand = "Cherry Delight";
	ptrBar[2].weight = 4.9;
	ptrBar[2].calories = 380;

	//display contents of each structure in the array
	cout << (ptrBar[0].brand).data() << " candy bar weighs " << ptrBar[0].weight
		<< " grams and contains " << ptrBar[0].calories << " calories.\n";
	cout << (ptrBar[1].brand).data() << " candy bar weighs " << ptrBar[1].weight
		<< " grams and contains " << ptrBar[1].calories << " calories.\n";
	cout << (ptrBar[2].brand).data() << " candy bar weighs " << ptrBar[2].weight
		<< " grams and contains " << ptrBar[2].calories << " calories.\n";

	cin.get();

	return 0;
}

There may well be more elegant ways of doing it!

Cobberas

This question has already been answered. Start a new discussion instead.