incompatible types in assignment of ‘Enemy*’ to ‘Enemy* [0]

Yes, I'm back again with the same project I'm always asking questions about. I'm on Linux, and my issue this time is
1
2
3
4
5
6
7
8
9
10
11
12
13
michael@caitlyn current-ourrpg $ make
g++    -c -o enemyparty.o enemyparty.cpp
enemyparty.cpp: In member function ‘void EnemyParty::placeEnemies()’:
enemyparty.cpp:6:11: error: incompatible types in assignment of ‘Enemy*’ to ‘Enemy* [0]’
   enemies = new Enemy[enemyCount];
           ^
enemyparty.cpp:9:31: error: conversion from ‘Enemy*’ to non-scalar type ‘Enemy’ requested
      Enemy myEnemy = enemies[x];
                               ^
          ^
<builtin>: recipe for target 'enemyparty.o' failed
make: *** [enemyparty.o] Error 1


Sadly,I have not learned anything since the last time I worked on this project about C++. I remember that an Enemy array is NOT an Enemy. My code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
ifndef ENEMYPARTY_H
#define ENEMYPARTY_H

#include "party.h"
#include "enemy.h"

const int MAXENEMYCOUNT = 12;
class EnemyParty : public Party
{
   public:
      EnemyParty(): enemyCount(0) {}
      ~EnemyParty() {}
      void placeEnemies();
      int getEnemyCount() { return enemyCount; }
   private:
      int enemyCount; //How many enemies there are in a party.
      Enemy* enemies[];
      
};
#endif
#include "enemyparty.h"

void EnemyParty::placeEnemies()
{
  //Create the enemies array
  enemies = new Enemy[enemyCount];
  for (int x = 0; x < enemyCount; x++)
  {
     Enemy myEnemy = enemies[x];
//     if (n % 4 == 0)
     {
        int i = n - 1;
        switch (i)
        {
           case 12:
      	     myEnemy.setX(200); 
      	     break;
           case 9:
      	     myEnemy.setX(100);
	     break;
           case 5:
             myEnemy.setX(0);
	     break;
        }
        myEnemy.setY(i/4);
     }
   }
}
#ifndef ENEMY_H
#define ENEMY_H

#include "character.h"

class Enemy : public Character
{
   public:
      Enemy(); 
      ~Enemy();
      void setCurrentSprite(int) {}
      Uint32 getColorKey() { return colorkey; }
      SDL_Surface* getImage();
   private:
      SDL_Surface *eimage;
      SDL_Rect esrc, edest;
      Uint32 colorkey;
};

#include "enemy.h"

Enemy::Enemy()
{
   //call Character::loadImage and do some other stuff TBD later
   Character::loadImage("imp.gif"); //TEMP
}

Enemy::~Enemy()
{
   if (eimage != NULL) SDL_FreeSurface(eimage);
}
SDL_Surface* Enemy::getImage()
{
/*     colorkey = SDL_MapRGB(eimage->format, 0, 0, 255);
     SDL_SetColorKey(eimage, SDL_SRCCOLORKEY, colorkey);
      
     esrc.x = 0;
     esrc.y = 0;
     esrc.w = eimage->w;
     esrc.h = eimage->h;
      
      
     edest.x = 0;
     edest.y = 100;
     edest.w = eimage->w;
     edest.h = eimage->h;
*/
     return eimage;
}

#endif 


If you need the Party class or the Character class to assist me, please say so and I will provide them. Character is rather long. That is why it's not provided here. Thank you in advance to anyone who can assist me with this issue.
Last edited on
You made enemies an array of pointer to Enemy, not an array of Enemy. It you want an array of pointers, then:

1
2
3
    enemies = new Enemy*[enemyCount];

    Enemy* myEnemy = enemies[x];

Last edited on
@msulli1355,

@dutch is right, but there's a step between you'll need to keep in mind. It's implied to us old hands, but since you're a beginner, keep in mind that an array of Enemy pointers doesn't have storage for enemies, just storage for pointers to enemies.

enemies = new Enemy *[ enemyCount ];

sometime....later, the missing step

enemies[ x ] = new Enemy(....);

So that Enemy * p = enemies[ x ] actually points to an enemy, and not random garbage that will crash.

This also means that before you're done, you'll need to walk through all of the enemies to delete them before deleting the enemies array.

This also brings up the point that declaring an enemy array may not automatically include zeroing out all the pointers. You may need to initialize them to zero for things to be sane.


I totally forgot to mention that.

But we both missed a detail, look how enemies is defined:

 
      Enemy* enemies[];


I don't remember what that's called, but you can leave out the array size if it's the last member of a struct/class, and then you are supposed to dynamically allocate that class with an extra amount of space for the array size that you want.

But it is perhaps more probable that @msulli1355 actually wanted plain old:

 
      Enemy* enemies;

all along.
@dutch, I must stop drive by posting
> Enemy* enemies[];
> I don't remember what that's called, you can leave out the array size if it's
> the last member of a struct/class
flexible array member, but that's a c99 feature
that's illegal in c++ and also we have std::vector
@ne555,

This:

1
2
3
4
5
class A
{
 int a;
 int *b;
};


Where A is constructed using "in place" syntax, given storage for an array can cause b to function as an array, even in modern C++.

More to the point:

1
2
3
4
5
template< typename T >class Node
{
 int refcount;
 T *;
};


Is the basis for using make_shared<> creating new node instances for shared_ptr using a unified node/object memory block, with in place construction, though I don't know if all implementations bother with T *, as they may merely calculate the position past Node.


Last edited on
@ne555, I thought it was from C99 but didn't realize it wasn't in C++. So they added the "flexible array" at the same time they added the hapless variable-length array. The flexible-array is apparently just syntactic sugar for the old "zero-length array" trick.

@Niccollo, "Flexible arrays" are not really compatible with inheritance, so I guess that's why C++ leaves it to low-level stuff. I was only able to get it to work like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>

struct Obj
{
    int n;
    int a; // space for 1 int, properly aligned
};

int main()
{
    constexpr int ArrSize = 50;
    constexpr int BufSize = sizeof(Obj) + (ArrSize - 1) * sizeof(int);

    char buf[ BufSize ];
    Obj* o = new (buf) Obj;

/* possible layout
00  o  n
04     a  (&a)[0]
08        (&a)[1]
0c        (&a)[2]  
10        (&a)[3]
14        (&a)[4]
*/
    (&o->a)[42] = 99;
    std::cout << (&o->a)[42] << '\n';
}

Last edited on
This is but one way I've seen it done (and used it), ugly as the casting is

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct Obj
{
 int n;
 int *a;

 Obj( int sz )
 : n( sz )
  {
   a = reinterpret_cast< int * >(reinterpret_cast< char * >(this) + sizeof( Obj ));
  }
};



int main()
{
 constexpr int ArrSize = 50;
 constexpr int BufSize = sizeof(Obj) + ArrSize * sizeof(int);

 char buf[ BufSize ];
 Obj *o = ::new (buf) Obj( ArrSize );

 o->a[49] = 5;

 return 0;
}


Though this approach treats "a" as a mere convenience, replacing what would otherwise have been a dynamically allocated array (using new int[ n ] );

That's the view of Node in make_shared of shared_ptr, where the node typically has a pointer to an object allocated with new, and that is used to reference the block beyond the end of the node, as the array is here.

That is not, granted, exactly what flexible arrays are in C, but a related notion.

A different version is to ignore any kind of pointer in the Obj class, but use an access function (a get) to calculate the pointer appropriate for the storage (merely sizeof( obj ) + this). This would more closely resemble the actual layout of the flexible arrays of c.

It isn't that the lexical convenience is implemented, but that object layout can be achieved, and so from a practical perspective the same kind of thing can be created where the objective is one block of RAM used for the "invention". For C++, a vector may be more appropriate, but if the objective is to consolidate storage and cut the second allocation (as it is with make_shared), these are the lines of thought which do that.



Last edited on
My code has changed slightly. I'm down to one error at least. When I was younger, I tried to gain experience with as many different programming languages as possible. I think the lines that dutch commented on are from my Java days. I need to shed those Java days if I ever expect to finish this project. My algorithm for this method is such, and I do realize that my VB code structure will not work in C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
michael@caitlyn current-ourrpg $ cat Notes/notes.txt 
Mob Placement algorithm:

If loop invariant % 4 == 0
{
   switch (i)
   {
      case i < 13:
      	xPos = 200; 
      	break;
      case i < 9:
      	xPos = 100;
	break;
      case i < 5:
        xPos = 0;
	break;
   }
   yPos = i/4;

}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[
michael@caitlyn current-ourrpg $ cat enemyparty.cpp
#include "enemyparty.h"

void EnemyParty::placeEnemies()
{
  //Create the enemies array
  enemies = new Enemy*[enemyCount];
  for (int x = 0; x < enemyCount; x++)
  {
     Enemy* myEnemy = enemies[x];
//     if (n % 4 == 0)
     {
        int i = 0;
        switch (i)
        {
           case 12:
      	     myEnemy->setX(200); 
      	     break;
           case 9:
      	     myEnemy->setX(100);
	     break;
           case 5:
             myEnemy->setX(0);
	     break;
        }
        myEnemy->setY(i/4);
     }
   }
}
michael@caitlyn current-ourrpg $ 

The error at present are:
1
2
3
4
5
6
7
g++    -c -o enemyparty.o enemyparty.cpp
enemyparty.cpp: In member function ‘void EnemyParty::placeEnemies()’:
enemyparty.cpp:6:11: error: incompatible types in assignment of ‘Enemy**’ to ‘Enemy* [0]’
   enemies = new Enemy*[enemyCount];
           ^
<builtin>: recipe for target 'enemyparty.o' failed
make: *** [enemyparty.o] Error 1
Originally the prototype for placeEnemies was
 
void EnemyParty::placeEnemies(int n)

I do realize that at this point I should probably not worry about code and figure out how to correct my algorithm, but I'm the sort who codes what he knows and runs from there. I've also learned in my researches yesterday that arrays of objects are generally frowned upon nowadays, and I should be using Vectors are std:arrays....
Last edited on
If you want an array of pointers, then declare enemies like this:

 
Enemy** enemies;


Last edited on
Now, my error list is longer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
michael@caitlyn current-ourrpg $ make
g++    -c -o enemyparty.o enemyparty.cpp
enemyparty.cpp: In member function ‘void EnemyParty::placeEnemies()’:
enemyparty.cpp:6:11: error: incompatible types in assignment of ‘Enemy**’ to ‘Enemy** [0]’
   enemies = new Enemy*[enemyCount];
           ^
enemyparty.cpp:16:22: error: request for member ‘setX’ in ‘* myEnemy’, which is of pointer type ‘Enemy*’ (maybe you meant to use ‘->’ ?)
             myEnemy->setX(200); 
                      ^
enemyparty.cpp:19:22: error: request for member ‘setX’ in ‘* myEnemy’, which is of pointer type ‘Enemy*’ (maybe you meant to use ‘->’ ?)
             myEnemy->setX(100);
                      ^
enemyparty.cpp:22:23: error: request for member ‘setX’ in ‘* myEnemy’, which is of pointer type ‘Enemy*’ (maybe you meant to use ‘->’ ?)
              myEnemy->setX(0);
                       ^
enemyparty.cpp:25:18: error: request for member ‘setY’ in ‘* myEnemy’, which is of pointer type ‘Enemy*’ (maybe you meant to use ‘->’ ?)
         myEnemy->setY(i/4);
                  ^
<builtin>: recipe for target 'enemyparty.o' failed
make: *** [enemyparty.o] Error 1
michael@caitlyn current-ourrpg $ 


And now I'm completely confused by the errors "(maybe you meant to use ‘->’ ?)" when I DID use the arrow thing as you can see in the error listing.
Show exactly how you declared enemies.
I realized that I forgot to give you the new enemyparty.h file. Here it is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
michael@caitlyn current-ourrpg $ cat enemyparty.h
#ifndef ENEMYPARTY_H
#define ENEMYPARTY_H

#include "party.h"
#include "enemy.h"

const int MAXENEMYCOUNT = 12;
class EnemyParty : public Party
{
   public:
      EnemyParty(): enemyCount(0) {}
      ~EnemyParty() {}
      void placeEnemies();
      int getEnemyCount() { return enemyCount; }
   private:
      int enemyCount; //How many enemies there are in a party.
      Enemy** enemies[];
      
};
#endif 
Enemy** enemies[];

What is this meant to be? Is this meant to be an array of Enemy objects?
A couple of posts back I told you to declare enemies like this:

 
Enemy** enemies;

This looks very wrong:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  Enemy myEnemy = enemies[x];
//     if (n % 4 == 0)
     {
        int i = n - 1;
        switch (i)
        {
           case 12:
      	     myEnemy.setX(200); 
      	     break;
           case 9:
      	     myEnemy.setX(100);
	     break;
           case 5:
             myEnemy.setX(0);
	     break;
        }
        myEnemy.setY(i/4);
     }



Enemy myEnemy = This creates a WHOLE NEW Enemy object, which is then thrown away at the end of the scope.

msulli1355 , do you realise that? This isn't like some other languages where Enemy myEnemy = creates a reference to some already existing object; in C++, this creates a WHOLE NEW object.
At least it builds now. I changed the enemies declaration in enemyparty.h to Enemy** enemies. myEnemy is simply meant as a shortened pointer to the enemies array as I work my way through it. The -> errors are gone too. It actually builds now. Thank you for all your help.
myEnemy is simply meant as a shortened pointer to the enemies array as I work my way through it.


So you were trying to have an array of Enemy objects? This being C++, we'd be remiss if we didn't say that you shouldn't really be using arrays. This is C++; we have vector for that sort of thing.
Last edited on
Topic archived. No new replies allowed.