Question

I started to write this code for fun and I was surprised that it compiled and worked. (I'm using Dev C++ to compile.) I wanted to create an array of structs but before I created the array, It stored and read the values like it was already an array. Why Is this, and how may I still create an array of structs so I can keep track of the total size of the array?

#include <iostream>
using namespace std;

struct Shape
{
 public:
 int x,y,z;
};

struct Triangle: public Shape
{
 public:
 int tNum;
};

struct Rectangle: public Shape
{
 public:
 int rNum;
 float differentNum;
};

struct Circle: public Shape
{
 public:
 int cNum;
}; 

int main(void)
{ int i;
 Triangle tri;
 Rectangle rec; 
 Circle cir; 
 Shape *arr[3]={&tri, &rec, &cir};

 for(i=1;i<5;i++){ arr[1][i].x=i*2; cout<<"set  tri["<<i<<"] "<<i*2<<endl;} cout<<endl; 
 for(i=1;i<5;i++){ arr[2][i].x=i*9; cout<<"set  rec["<<i<<"] "<<i*9<<endl;} cout<<"-----------------"<<endl;

 for(i=1;i<5;i++){ cout<<"read tri["<<i<<"] "<<arr[1][i].x<<endl;} cout<<endl;
 for(i=1;i<5;i++){ cout<<"read rec["<<i<<"] "<<arr[2][i].x<<endl;}

 system("pause");
 return(0);
}

/*output   
set  tri[1] 2   
set  tri[2] 4  
set  tri[3] 6  
set  tri[4] 8  

set  rec[1] 9  
set  rec[2] 18  
set  rec[3] 27  
set  rec[4] 36  
-----------------`  
read tri[1] 2  
read tri[2] 4  
read tri[3] 6  
read tri[4] 8

read rec[1] 9  
read rec[2] 18  
read rec[3] 27  
read rec[4] 36*/
Was it helpful?

Solution

You have an array of 3 Shape* variables, each pointing to a valid Shape instance in the stack:

  • arr[0] is pointing to the tri instance, so arr[0][0] is the tri instance.
  • arr[1] is pointing to the rec instance, so arr[1][0] is the rec instance.
  • arr[2] is pointing to the cir instance, so arr[2][0] is the cir instance.

Any other use of arr is basically illegal (even though it might work).

Although it is not recommended, the fact that the rec instance and the cir instance appear in the stack immediately after the tri instance, allows you to use arr in a few other ways and "stay alive":

  • arr[0][1] is the rec instance, which appears in the stack after the tri instance.
  • arr[0][2] is the cir instance, which appears in the stack after the rec instance.
  • arr[1][1] is the cir instance, which appears in the stack after the rec instance.

As pointed out in one of the comments below, it really depends on the implementation of the stack.

Any other (different) attempt to access memory through arr is a potential memory access violation.

Here is how you should probably do it:

#include <string>
using namespace std;

class Shape
{
protected:
    Shape() {}
    virtual ~Shape() {}
    string type;
    int x,y,z;
public:
    string GetType() const {return type;}
    void SetX(int val) {x = val;}
    void SetY(int val) {y = val;}
    void SetZ(int val) {z = val;}
};

class Triangle : public Shape
{
public:
    Triangle():type("Triangle") {}
    void SetNum(int val) {tNum = val;}
private:
    int tNum;
};

class Rectangle : public Shape
{
public:
    Rectangle():type("Rectangle") {}
    void SetNum(int val) {rNum = val;}
    void SetDifferentNum(float val) {differentNum = val;}
private:
    int   rNum;
    float differentNum;
};

class Circle : public Shape
{
public:
    Circle():type("Circle") {}
    void SetNum(int val) {cNum = val;}
private:
    int cNum;
};

...

Triangle  tri;
Rectangle rec;
Circle    cir;
Shape*    arr[3] = {&tri, &rec, &cir};
int       size = sizeof(arr)/sizeof(*arr);
for (i=0; i<size; i++)
{
    arr[i]->SetX(i*2);
    cout << "set " << arr[i]->GetType() << "[" << i << "] = " << i*2 << endl;
}

OTHER TIPS

You have some seriously undefined behavior going on here; your code is not doing what you may think it's doing. for example, arr[2] is a pointer to cir, but arr[2][1] and arr[2][2] are pointers to uninitialized blocks of memory. From your definition

Shape *arr[3]={&tri, &rec, &cir};

you can safely access arr[0] (a pointer to tri), arr[1] (a pointer to rec) and arr[2] (a pointer to cir), but that's all.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top