Pointers... NEW.... -- How to create an array specifying the size "behind"

Hello, I have a kind of structure like that in an external file estructura.h

#include <Arduino.h>

struct TBoton
{ char nombrebt[13];
  boolean estado; 
 };

struct TZona
{
  char nzona[13]; 
  TBoton boton[8];  
};

As you can see, I have specified the size of “TBoton boton” (in our case 8)

I would, in my main skectch, read a value, and create the structure with the size I have read.

I have been reading, and I think I understand more or less the idea of using pointers …when I use … TBoton *ptrboton, ptrboton can recieve &miboton (the address)… and work like ptrboton-> in my structure…

But I don’t have clear how to create the structure… using NEW … sending the value for the size or my array…

Changes in structure.h ???

Sintaxis for the NEW … in the main skectch ???

Thank you very much…

malloc() is used to request an area of memory of variable size. It is not used very often on an Arduino because the memory is so small that you have to know at all times how much memory your program is using so that you can keep it small enough to fit.

Usually you should use a normal fixed array to reserve an area big enough for what you need and then keep your own count for how much of it is filled.

Maybe, something like this ?

// Global pointer to TZona
TZona *Ptr_TZona;
    
setup()
{
    size_t  Buffer_Size_Needed;
    int     Number_Of_Structures;

    // Get the number of TZona structures needed
    Number_Of_Structures = Get_Number_Of_Structures();

    // Calculate the buffer size needed
    Buffer_Size_Needed = sizeof( TZona ) * Number_Of_Structures;

    // Allocate the Buffer and set Global TZona Pointer
    Ptr_TZona = (TZona *)malloc( Buffer_Size_Needed );

    // If malloc failed ?
    if (!Ptr_TZona )
    {
         // Complain now!
        Buffer_Failed();
    }
}

Loop ()
{

// Use the Global TZona Pointer here 

}

You are going to do this ONCE, in SETUP(), right?

Or if you particularly want to use 'new', as you asked:-

struct TBoton
{
    char nombrebt[13];
    boolean estado;
};

struct TZona
{
    char nzona[13];
    TBoton boton[8];
};

int Get_Number_Of_Structures()
{
    return 12;     // *** Temporary value for test
}

// Global pointer to TZona
TZona *Ptr_TZona;

void setup()            // *** 'Commented' out unneeded 'malloc()' stuff. ***
{
    //    size_t  Buffer_Size_Needed;
    int     Number_Of_Structures;

    // Get the number of TZona structures needed
    Number_Of_Structures = Get_Number_Of_Structures();

    // Calculate the buffer size needed
    //    Buffer_Size_Needed = sizeof( TZona ) * Number_Of_Structures;

    // Allocate the Buffer and set Global TZona Pointer
    //    Ptr_TZona = (TZona *)malloc( Buffer_Size_Needed );

    Ptr_TZona = new TZona[Number_Of_Structures];

    // If malloc failed ?
    if (!Ptr_TZona )
    {
        // Complain now!
        //        Buffer_Failed();  // *** Temp removed to allow compilation
    }
}

void loop ()
{

    // Use the Global TZona Pointer here

}

It's still better to avoid dynamic memory allocation if you can. It can quickly lead to memory fragmentation.

First of all, really thank you very much for all of you. I am quite new here and I am learning a lot.

I will try the second option with NEW seems easiest for me, althoguht the final struct is a little more complex.

I tell you the final structure... the question is that there is another level.... I mean.... One site with several zones with some buttons per zone..... so the first level....

struct MSite
{
 char nsite[13];  
 TZona mizona[4];

How would it be now????

a - I do the second option for Tzona and I create the number "on the fly". I get my Ptr_TZona.

b - I do the next level, the same for MSite with NEW, I would like to fix the number of zonas "on the fly". I get my Ptr_MSite.

How do I connect Ptr_Msite with Ptr_TZona ?????

How do I "work" with the whole structure ????

Working with the structure define the sizes before was simple....

1 - To work: vmsite.vmizona[3].vboton[0].nombrebt ------- and now????

2 - Before that, I send &vmiste to an external procedure to work with the structure.... and I working like this: ptrmiste->vmizona[3].vbont[0].nombrebt ----------- and now ????

OK, I think I got it: multiple sites with multiple zones, with multiple buttons per zone?

The memory on an Arduino is so limited that it's not usually worthwhile adding in the complexity of variable sizes. 10 sites with 10 zones with 10 buttons will fill ALL the memory on an Arduino UNO, with nothing left over for your program to actually do anything.

Can you identify which one will vary the most? Will most zones have one button but there's one or two zones in your proposed sites that have more than 10 buttons? Then make the other sizes fixed - allow only 10 sites and a maximum of 5 zones per site.

One data structure that might help you is the "linked list." It's taught very early on in computer science classes but it's actually very rare to use one in a real program. This seems like it might be a candidate for that, since the buttons per site is highly variable - you don't want to have lots of sites with 1 button occupying the same memory size as the largest possible site.

MorganS: OK, I think I got it: multiple sites with multiple zones, with multiple buttons per zone?

The memory on an Arduino is so limited that it's not usually worthwhile adding in the complexity of variable sizes. 10 sites with 10 zones with 10 buttons will fill ALL the memory on an Arduino UNO, with nothing left over for your program to actually do anything.

Can you identify which one will vary the most? Will most zones have one button but there's one or two zones in your proposed sites that have more than 10 buttons? Then make the other sizes fixed - allow only 10 sites and a maximum of 5 zones per site.

One data structure that might help you is the "linked list." It's taught very early on in computer science classes but it's actually very rare to use one in a real program. This seems like it might be a candidate for that, since the buttons per site is highly variable - you don't want to have lots of sites with 1 button occupying the same memory size as the largest possible site.

Hello Morgan.I am using Arduino Mega. And well, it would be enough creating "dinamically" the main level, I mean.... the Tzona of MSite....

It is just a question of "elegance" and a way to save memory... I mean... I don't want to reserve memory for 8 zones if I am going to work with 4.

So we have this:

estructura.h

struct MSite { char nsite[13]; //the neme of the site TZona mizona[8]; //the zones ... with their buttons in next leves.... }

Now the main sketch read THE WHOLE STRUCTURE AND THE NUMBER OF ZONES from the EEPROM.

like this.... (it is less important but I tell you JUST to understand what is miMemoria.dato.sitio and miMemorial.dato.nZonas)

struct CONFIG{ int nZonas; MiSitio sitio; };

union MEMORIA{ CONFIG dato; byte b[sizeof(CONFIG)]; } miMemoria;

so at last I have --- this is the important

miMemoria.dato.sitio that is MSite miMemoria.dato.nZonas that is the number of zones I will work

if I do it ...

int *p = &miMemoria.dato.nZonas; int numberZones = *p;

Now I will have exacly then number of zones in zones in numberZones.

Well now... I send the address of MSite to manage like that...

manage(&miMemoria.dato.sitio);

.... I am working with

struct MSite { char nsite[13]; //the neme of the site TZona mizona[8]; //the zones ... with their buttons .... }

and imagine I have just 4 zones.... so I would like to have the same and work but using memory for 4 (miMemoria.dato.nZonas) zones and no for 8 ......

I am Spanish... I don't know if I have being clear enough....

Any help?

Thank you

and imagine I have just 4 zones.... so I would like to have the same and work but using memory for 4 (miMemoria.dato.nZonas) zones and no for 8 ......

You MUST use malloc() or new() to allocate space for dynamically sized zones. You can NOT expect the compiler, at run time, to generate different amounts of space based on what might be on the SD card at run time.

I am Spanish... I don't know if I have being clear enough....

What you want to do is clear enough. You just don't seem to know how to do it.

PaulS: You MUST use malloc() or new() to allocate space for dynamically sized zones. You can NOT expect the compiler, at run time, to generate different amounts of space based on what might be on the SD card at run time. What you want to do is clear enough. You just don't seem to know how to do it.

I tell you what I am trying:

I change the structure for not having limits.....

struct MiSitio { char nsite[16]; //the name TZona mizona[]; //the zones};

... in the main sketch

Tzona *ptr_Zonas; MiSitio *ptr_Sitio;

ptr_Zonas = new TZona[numberOfZones]; ptr_Sitio = new MiSitio();

and now I try to mount the site...

ptr_Zonas = miMemoria.dato.sitio.mizona; ptr_Sitio->nsite = miMemoria.dato.sitio.nsite; ptr_Sitio->mizona = ptr_Zonas;

but I am getting in that line: ptr_Sitio->nsite = miMemoria.dato.sitio.nsite;

invalid array assigment

interfaceprom.ino: In function 'void setup()': interfaceprom:48: error: invalid array assignment interfaceprom:49: error: incompatible types in assignment of 'TZona*' to 'TZona [0]' invalid array assignment

I change the structure for not having limits.....

struct MiSitio { char nsite[16]; //the name TZona mizona[]; //the zones};

You have successfully defined a 0 element array. Useless.

EVERY level will need to be either a fixed length array, like nsite, OR a pointer to dynamically allocated memory. 0 length arrays are USELESS.

PaulS: You have successfully defined a 0 element array. Useless.

EVERY level will need to be either a fixed length array, like nsite, OR a pointer to dynamically allocated memory. 0 length arrays are USELESS.

Well... the question is not to specified the size.... to do it dinamically ..... I think the structure in estrctura.h must be defined like that, no????

MMMmmmm.... I think the problem is that the new MiSitio define "another more" .... TZona and without elementos...... so I think I am looking for something lika that:

new MiSitio("the name os the site",new TZona[numberOfZones]);

A kind of "constructor" ???? It would have difined in the estructura.h file ????

TZona mizona[]; //without size because I will define dinamically ....

  TZona mizona[]; //without size because I will define dinamically ....

Nonsense.

  TZone *pmizona; // I will define dinamically

THIS is the way to define that you want to point to some memory that you will dynamically, using new or malloc(), allocate later.

PaulS:   TZona mizona[]; //without size because I will define dinamically ....

Nonsense.

  TZone *pmizona; // I will define dinamically

THIS is the way to define that you want to point to some memory that you will dynamically, using new or malloc(), allocate later.

Mmm, it seems we are approaching.... mmm

So to do what I want... first of all the strcut of MSitio would be like that:

struct MiSitio { char nsite[16]; //the name TZona *ptr_zonas; //the zones}; }

and now...

Tzona *ptr_Zonas; MiSitio *ptr_Sitio;

ptr_Zonas = new TZona[numberOfZones]; ptr_Sitio = new MiSitio();

So... how I write that ptr_Sitio -> ptr_zonas = ptr_Zonas ...... I mean... I want to "mount" the whole site ....

Mmm... well it seems that as I wrote ------------ ptr_Sitio -> ptr_zonas = ptr_Zonas.

By the time you get done, you'll find that implementing classes for the zones and cities is going to make a lot more sense.

Well... I don't see at all... so many changes.... and a library I defined .... where I send the address like

&misitio

and I work inside the library like

ptro_misitio->mizona[n] ........

with the original structure

struct MiSitio { char nsite[16]; TZona mizona[8];

};

and I loose myself if I use

struct MiSitio { char nsite[16]; TZona *ptro_Zonas

};

I think it has to be simplier

I think it has to be simplier

Then forget about dynamic sizing. Pick a maximum number of zones and a maximum number of cities per zone.

Otherwise, stop waving your arms around, and post specific questions. A function that expects an array can not tell that it got a pointer, instead. In fact, a function that expects an array will ALWAYS get a pointer (to the first element of the array).

MorganS:
malloc() is used to request an area of memory of variable size. It is not used very often on an Arduino because the memory is so small that you have to know at all times how much memory your program is using so that you can keep it small enough to fit.

Usually you should use a normal fixed array to reserve an area big enough for what you need and then keep your own count for how much of it is filled.

That’s true. But if you don’t know the size of the data elements in advance, it’s an option. It’s safe as long as you pay attention to available memory when you allocate, and don’t ever re-allocate using free(). C++ has no garbage collection.

I think you can’t trust the return value from malloc() in this environment to manage the amount of remaining memory, because I doubt that it is smart enough to leave sufficient stack space. I admit I haven’t played with it yet.

I think you can't trust the return value from malloc() in this environment to manage the amount of remaining memory

The return value from malloc() is either a pointer to the memory that it allocated, or a NULL pointer if sufficient memory was not available. It tells you nothing about how much memory is still available.

PaulS:
The return value from malloc() is either a pointer to the memory that it allocated, or a NULL pointer if sufficient memory was not available. It tells you nothing about how much memory is still available.

Exactly. So if you don’t check the remaining memory separately, you will destroy the stack.

So if you don't check the remaining memory separately, you will destroy the stack.

How? Not by using malloc() or new. Both check to see that there is sufficient available memory [u]at the time that the function is called[/u] before allocating any memory.