Assigning one array to another

I'm trying to build a class, but since I can't redimension arrays, it's proving a little difficult

here's what I have

class Map2d{
public:
  byte Map[0][0];
  byte rows;
  byte columns;

 Map2d(byte _columns, byte _rows){
   rows = _rows;          
   columns = _columns; 
   byte NewMap[columns][rows]; //create the correct sized map
   &Map = &NewMap;              //doesn't compile
   }
 };

The sticking point is the last statement.. I've declared Map as a 2 dimensional map, and created a new map which is the correct size, I just can't seem to assign it to the one that will be used.

I haven't had a whole lot of experience with pointers, so that could be some of my hangup, I think you see what I'm trying to accomplish. I will have several of these maps, and they need to be stored to EEPROM, the largest will be about 15x10, and I'll have some smaller ones as well as well as a whack of other stuff I'll need to save to EEPROM, so I'll need as much room there as possible

If you have two arrays and you want to copy the elements of one array, to the other array, then you can copy each element, one at a time.

If you know what you are doing, you can use the memcpy( ) function.

Unlike some other languages, there is no direct assignment operator from an array to another array.

If you have only one actual array, you can have two different pointers pointing to it. The name of the array is in fact already a pointer, so you would not use the & prefix.

Your declaration of Map as a zero-element array looks wrong to me.

To allocate an array with a variable size inside a class, you use dynamically allocated memory. you also have to write a destructor for the object, if you need to re-use the memory.

I'd write something like this, because I don't like 2d arrays when they are dynamically allocated

class Map2d{
public:
  byte rows;
  byte columns;
  void set( uint8_t row,  uint8_t col, byte val);
  byte get( uint8_t row, uint8_t col);
private:
  byte* data ;

public:
 Map2d(byte _columns, byte _rows){
   rows = _rows;         
   columns = _columns;
   int size = rows*columns ;
   data = new byte[size] ;
   }

  ~Map2d() { delete[] data ; }

   void set( uint8_t row,  uint8_t col, byte val ) {  data[ row*columns + col ] = val ;}
   byte get( uint8_t row, uint8_t col)  { return data[ row*columns +col ] ; }
 };

Your Map2d class contains a map as part of its content. Look at it this way- at compile time, way is sizeof(Map2d)?

What you need is for the class to contain a reference, a pointer to a map that is allocated externally to the object.

Since the compiler does not know at compile time how big the rows and columns are, it's not possible to use array syntax to talk about the array. If you want to do that, then you will need to use operator overloading in the Map2d class.

So,

byte *map;
byte rows;
byte columns;

Map2d(byte _columns, byte _rows){
   rows = _rows;          
   columns = _columns; 
   map = new byte[columns*rows]; // or use malloc
};

byte get(int r, int c) {  return map[r*columns + c];}
void set(int r, int c, byte v) {  map[r*columns + c]  = v;}

I was hoping to be able to continue using a 2 dimensional array, as I have a lot of code based on it already, but it looks like I'll be changing it to 1 dimension.

PaulMurray
At compile time, it will be of size 0, I will read EEPROM data that will have the size of the array as well as the data to put in it.

Also, I will not need to dispose of it, it will continue to be used, perhaps with a couple changes to some of the values it contains.

Thanks for the pointers (groan).. I'll think about how I'm going to go about restructuring my data now... but not tonight.. I have a brain-ache.

michinyon:
If you have two arrays and you want to copy the elements of one array, to the other array, then you can copy each element, one at a time.

If you know what you are doing, you can use the memcpy( ) function.

Unlike some other languages, there is no direct assignment operator from an array to another array.

If you have only one actual array, you can have two different pointers pointing to it. The name of the array is in fact already a pointer, so you would not use the & prefix.

So are you saying that in my example Map = NewMap should work? I'm not concerned about the contents of the arrays, they're all 0 at this point, I'm just trying to get the previously undefined bound of Map to get properly defined, I though if I created a new array of the right size once I knew what the size was, I'd be able to assign it

Thinking about this a little more..., and as Paul was suggesting

How about if I did something like

byte Map1[2][3]; 
byte Map2[20][3];


class Map2d{

public:
byte rows;
byte columns;

  Map2d(byte NewMap[][], byte _columns, byte rows){
rows = _rows;
columns = _columns;
.
.
.

  byte somefunction(Map[][]){
  //do some work here
  return somebyte;
  }
};


Map2d Map1instance(Map1, 2,3);

Map2d Map2instance(Map2, 20,30);

void loop(){

 byte returnval1 = Map1instance(Map1); //all functions of an instance will require the external map to be passed as an argument.. a downside, but workable

 byte returnval2 = Map2instance(Map2);
}

So with this, as Paul said, the map is external to the class, that's OK for me at this point, the class will know the bounds of the array as it's passed in the constructor, the data in the maps may change, but the bounds will not. The downside is I'll always have to pass the array to the class if it needs to do any work with the map (probably always will), and you just have to be careful to pass the right map to it (certainly the right SIZE map).

Any thoughts, and potential problems with this kind of a solution?

Perhaps at the beginning of my class, I could have a reference to the external map.. As I said, i'm not too familiar with pointers, so correct me if need be

class Map2d{
private:

byte map*; //ADDED THIS

public:
byte rows;
byte columns;

  Map2d(byte NewMap[][], byte _columns, byte rows){

map = Newmap; //ADDED THIS TOO

rows = _rows;
columns = _columns;

.
.
.

  byte someNEWfunction(){

  //do some work here using the reference to map
  return somebyte;
  }

OK, here's what I want to do, in VB (this is the .NET micro framework for Netduino).. it's really simple and it took me 3 minutes to write

Module Module1
    Private Map1 As New Map2d(14, 9)
    Private Map2 As New Map2d(7, 5)

    Sub Main()
        ' write your code here
        Dim var1 As Integer = Map1.Somefunction(1, 5)
        Dim var2 As Integer = Map2.Somefunction(5, 2)

    End Sub

    Class Map2d
        Public Map(,) As Byte
        Public Xlabels() As UInteger
        Public Ylabels() As UInteger
        Public Rows As Byte
        Public Columns As Byte

        
      Public Sub New(ByVal _Columns As Byte, ByVal _Rows As Byte)
            Rows = _Rows
            Columns = _Columns

            ReDim Map(Columns, Rows)
            ReDim Xlabels(Columns)
            ReDim Ylabels(Rows)
        End Sub

        Public Function Somefunction(ByVal x As Byte, ByVal y As Byte) As Integer
            Dim somenumber

            Return somenumber
        End Function
    End Class

End Module

Is this really impossible to do in C++?

So are you saying that in my example Map = NewMap should work?

As a pointer assignment, yes, that would be correct syntax. But the declaration which precedes it, is wrong and won't work.

I was hoping to be able to continue using a 2 dimensional array

You probably can, there would be some way to do it.

There are about three ways you can have a 2-d array.

One way is to use a 1-d array and do the indexing calculations yourself. As in my example.

The second way is to use the ordinary 2-d array. However, I don't know if this is possible with dynamically allocated memory. And, to have a variable size array encapsulated inside a class, you need to use dynamically allocated memory.

Third way is to create you 2-d array more literally as an array of arrays. This requires more space as you then require an array of pointers to each of the rows of the array. On the other hand, the rows can be variable length and don't have to be contiguous in RAM. An array of strings is typically implemented this way, and you could do it with dynamically allocated memory, inside a class object. However this takes more space and has more overhead for many types of calculations.

From my test, it seems that Map = Newmap doesn't work if they aren't the same size,... which brings me right back to my original problem.

I think at my skill level arrays of arrays would quickly confuse the heck out of me in C++... I do use them in VB however.

In the end it really does look like the only reasonable solution to this is a 1d array and figure the rest out from there.

I though if I created a new array of the right size once I knew what the size was, I'd be able to assign it

Yes, you can. But only with using dynamically allocated memory ( "new", or malloc( ) ).

If you want to use an elementary array declaration, the size has to be known at compile-time, not when you try to instantiate the object.

Any thoughts, and potential problems with this kind of a solution?

Sorry I couldn't figure out what you were actually trying to achieve in reply #6. If you have your two globally declared arrays, and you know when you write your code what the size of the two of them are, then why bother with the whole class thing at all ? Just use the arrays.

byte map*; //ADDED THIS

This is not valid syntax.

It is possible, to refer to the pointer to a 2-d array, as

byte** map ;

where the type of the identifier map is "pointer to pointer to byte".

Is this really impossible to do in C++?

This seems easy to do in C++. Using the code I had in reply #2 yesterday

class Map2d{
public:
  byte rows;
  byte columns;
  void set( uint8_t row,  uint8_t col, byte val);
  byte get( uint8_t row, uint8_t col);
private:
  byte* data ;

public:
 Map2d(byte _columns, byte _rows){
   rows = _rows;         
   columns = _columns;
   int size = rows*columns ;
   data = new byte[size] ;
   }

  ~Map2d() { delete[] data ; }

   void set( uint8_t row,  uint8_t col, byte val ) {  data[ row*columns + col ] = val ;}
   byte get( uint8_t row, uint8_t col)  { return data[ row*columns +col ] ; }

   int somefunction ( uint8_t r,  uint8_t c ) ;
 };


void main ( )
{
     Map2d Map1 = Map2d( 9, 14 );      //  the argument here is  columns, rows,  for some stupid reason
     Map2d Map2 = Map2d( 5, 7 );

     int temp1 = Map1.somefunction ( 1, 5 ) ;
     int temp2 = Map2.somefunction ( 5, 2 ) ;

     int* var1 = new int[ temp1 ];
     int* var2 = new int[ temp2 ];
}

It is also possible to specify arrays in some circumstances, by specifying all of the dimensions except the first dimension.

You can write something like

int a[10] ;

The reason for this, is that when you then refer to a[ i ][ j ], the actual index into the 1-d array is calculated as 10*i + j , and for this, you need to know that the second dimension is 10, but you don’t need to know what the first dimension is.

I try to avoid this method because I find it confusing, but in some situations it is very useful, and some people use it a lot. Also, different generations of C have changed the rules for this, which I also find confusing.

Here’s an example

int fun(  int a[][4][4],  int len ) 
{
    int ans=0;
    // calculate something
    for ( int i=0 ; i<len ; i++){
       for ( int j=0 ; j<4 ; j++) {
          for ( int k=0 ; k<4 ; k++ ){
            ans+=a[i][j][k] ;
        }
      }
    }
    return ans ;
}



int main( )
{
      int b[100][4][4] ;
      int c[200][4][4] ;

      int ans1 = fun( b,  (sizeof(b)/(16*sizeof(int))) ) ;
      int ans2 = fun( c, ( sizeof(c)/(16*sizeof(int))) ) ;
}

Actually, that’s a bad example. If you want to use the functionality of incompletely specified array dimensions, I’m sure there is a good explanation, somewhere.

Michinyon, I have decided to go with a 1dimensional array and do the behind the scenes calculations myself.. the math really wasn't that bad, and I think it will reduce confusion later...

So here is what I got, I hope you can see what I'm trying to do, and correct me in my (many) mistakes

#include "Arduino.h"
#include "Map2d.h"


  byte* Map1d; //this is what I want to use to refer to the array, syntax certainly wrong.

  byte Rows; 
  byte Columns;
  

  Map::Map(byte _Columns, byte _Rows){
    Columns = _Columns;
    Rows = _Rows;
    
//Now that I know the size of the array I need, create it
    byte TheRealMap[Columns*Rows-1]; 


//this is the sticking point, assigning the the array I just created to the pointer.. certainly missing some * or &'s
   Map1d = TheRealMap; 
      
  }

I'm not familiar with using new or malloc(), or where the uses are applicable

Normal array indexing is [row][column] , it's probably a good idea to change to that.

//Now that I know the size of the array I need, create it
byte TheRealMap[Columns*Rows-1];

You can't do this. Those sizes have to be discernable at compile-time, and they are not.

If you want to do this from your object constructor, you need to have

   byte* TheRealMap = new byte[ Columns*Rows ] ;    // dynamically allocated memory

   byte TheRealMap[] = new byte[ Columns*Rows ] ;    // this would be equivalent, I think

And, I don't know why you would subtract 1 from the size of the array, that just seems strange.

//this is the sticking point, assigning the the array I just created to the pointer.. certainly missing some * or &'s
Map1d = TheRealMap;

This would assign another pointer which points to the same array. But, it is not the "sticking point". The creation of the array is the sticking point. If the creation of the array was valid, this would work. But it would not be copying the array, you would just have two different pointers to the same array.

Sorry about subtracting 1.. it's a leftover from VB differences.. in VB you declare the upper bound, in C you declare the number of elements.

I don't quite understand how

byte* TheRealMap = new byte[ ColumnsRows ] ; // dynamically allocated memory
byte TheRealMap[] = new byte[ Columns
Rows ] ; // this would be equivalent, I think

would be different from
byte TheRealMap[Columns*Rows];
when used in the constructor to create the array.

Unless there's a better way, assigning a pointer (byte Map1d) to point to that array is what I'm trying to do.. I just can't get it to work and don't know where I'm going wrong..

If I have a pointer to that array, I should be able to do pointer arithmetic to iterate through the array right?

So once I get the syntax of Map1d = TheRealMap I should be good

Thanks for your help so far too

I don't quite understand how

byte* TheRealMap = new byte[ ColumnsRows ] ; // dynamically allocated memory
byte TheRealMap[] = new byte[ Columns
Rows ] ; // this would be equivalent, I think

would be different from
byte TheRealMap[Columns*Rows];
when used in the constructor to create the array.

Because, in order to allocate the space for the array, the compiler needs to know the size, when the compiler runs. And, it doesn't ! "Columns" and "Rows" are not constants.

If "you don't understand" that, you should perhaps read about how compilers actually work, and how memory space for program variables actually works.

I just can't get it to work and don't know where I'm going wrong..

I've told you where you are going wrong.

So once I get the syntax of Map1d = TheRealMap I should be good

I don't think so. You have a one-track mind. The syntax of this pointer assignment is not your real problem.

If you know what size these arrays are going to be, just declare them as arrays with known sizes in your sketch and be done with it, get rid of the class altogether, it doesn't do anything useful for you.

OK, I’ll post the entire class that I wrote in VB, and works well.

Most of the private functions can be ignored, they’re all with the nitty-gritty of interpolating values from between the cells

I was hoping this could be written in C as well

Public Class Map2d

    Private Map1d() As Byte
    Public Rows As Byte
    Public Columns As Byte
    Public RowLabels() As Integer
    Public ColumnLabels() As Integer

    Public Property Map_1d As Byte()
        Get
            Return Map1d
        End Get
        Set(value As Byte())
            If UBound(value) <> UBound(Map1d) Then 'I want to be sure we don't/can't change the size of the internal map.. that's a receipe for disaster
                Throw New IndexOutOfRangeException
            Else
                Map1d = value
            End If
        End Set
    End Property

    Public Sub New(Columns As Byte, Rows As Byte)
        Me.Rows = Rows
        Me.Columns = Columns

        ReDim Map1d(Rows * Columns - 1)
        ReDim ColumnLabels(Columns - 1)
        ReDim RowLabels(Rows - 1)

    End Sub
    
Default Public Property Map(Column As Byte, Row As Byte) As Integer
        Get
            Return Map1d(GetMapIndex(Column, Row))
        End Get
        Set(value As Integer)
            Map1d(GetMapIndex(Column, Row)) = value
        End Set
    End Property

    Public Function Interpolate(Xvalue As Integer, Yvalue As Integer) As Single
        Dim ColumnIndex As Byte = GetLabelIndex(ColumnLabels, Xvalue)
        Dim RowIndex As Byte = GetLabelIndex(RowLabels, Yvalue)
        Dim FourCornersValues(,) As Byte = GetFourCornersValues(ColumnIndex, RowIndex)
        Dim FourCornersLabels(,) As Integer = GetFourCournersLabels(ColumnIndex, RowIndex)
        Dim outval As Single = Remap2d(Xvalue, Yvalue, FourCornersValues, FourCornersLabels)
        Return outval
    End Function
    
Private Function Remap2d(Xval As Integer, Yval As Integer, FourCornersValues(,) As Byte, FourCornersLabels(,) As Integer) As Single
        'does a 3d map interpolation to find the values between cells
        Dim a As Single = Remap(Xval, FourCornersLabels(0, 0), FourCornersLabels(0, 1), FourCornersValues(0, 0), FourCornersValues(1, 0))
        Dim b As Single = Remap(Xval, FourCornersLabels(0, 0), FourCornersLabels(0, 1), FourCornersValues(0, 1), FourCornersValues(1, 1))
        Dim c As Single = Remap(Yval, FourCornersLabels(1, 0), FourCornersLabels(1, 1), a, b)
        Return c
    End Function

    Private Function GetMapIndex(Column As Byte, Row As Byte) As Integer
        Dim index As Integer = Column + Row * Me.Columns
        Return index
    End Function

    Private Function GetLabelIndex(Labelarray() As Integer, Value As Integer) As Byte
        For i As Integer = UBound(Labelarray) - 1 To 0 Step -1
            If Value > Labelarray(i) Then Return i
        Next
        Return 0
    End Function

    Private Function GetFourCornersValues(ColumnIndex As Byte, RowIndex As Byte) As Byte(,)
        Dim outbytes(1, 1) As Byte
        outbytes(0, 0) = Map(ColumnIndex, RowIndex)
        outbytes(1, 0) = Map(ColumnIndex + 1, RowIndex)
        outbytes(0, 1) = Map(ColumnIndex, RowIndex + 1)
        outbytes(1, 1) = Map(ColumnIndex + 1, RowIndex + 1)
        Return outbytes
    End Function

    Private Function GetFourCournersLabels(ColumnIndex As Byte, RowIndex As Byte) As Integer(,)
        'return is out(X=0 Y=1, Low = 0 High =1)
        Dim Outints(1, 1) As Integer

        Outints(0, 0) = ColumnLabels(ColumnIndex)
        Outints(0, 1) = ColumnLabels(ColumnIndex + 1)
        Outints(1, 0) = RowLabels(RowIndex)
        Outints(1, 1) = RowLabels(RowIndex + 1)
        Return Outints
    End Function
   
   Public Shared Function Remap(value As Single, oldlow As Single, oldhigh As Single, newlow As Single, newhigh As Single) As Single

        Dim rval As Single = (value - oldlow) / (oldhigh - oldlow) * (newhigh - newlow) + newlow
      
        Return rval
    End Function

End Class

Sorry if I’m sounding stubborn… C++ has always been extolled as such a powerful language I thought something as simple as this wouldn’t be such a big problem. I will continue to dig into it… I had a whack of Ebooks on C, but the PDF files seem to have all gotten corrupted… I’ll have to try and get them again.

I'll fix the columns/rows backwardness too...

I somehow missed your example in reply 11... that seems to do what I want.. will work with it a bit and see what I can do with it... Will let you know... How do I buy you a beer?