Dynamic array of structs error

Go To Last Post
20 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hey guys,
I'm currently trying to make a dynamic array of structs with the fucntion Malloc.

uint8_t N;
typedef struct {
	uint8_t Adres;
	uint8_t Adres_read;
	uint8_t Adres_write;
	uint8_t Adres_register;
}Sensor;

Sensor *Sensoren =(Sensor*)malloc(N*sizeof(Sensor));
        Sensoren[0].Adres = value;
	Sensoren[0].Adres_write = value;
	Sensoren[0].Adres_read = value;
        Sensoren[0].Adres_register = value;

After i try to compile this code i can de error that the element is not const. Pointing were i use malloc function.
Correct me if i'm wrong, but if i make it const i can write value to it anymore because in const and may not be changed.
I have search for answers but i couldn't find 1 that worked.
I hope you guys could help me.
Thanks in advance.

Last Edited: Mon. Jan 13, 2014 - 02:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
de error that the element is not const.

uint8_t N; 

de error that the element is not const or de error that it is not initialized prior use?

Perhaps it is because of your reduced malloc implementation? avr-libc?
I would also suggest an

assert(Sensoren);

(at least)

EDIT: You are aware that malloc() is a function, not a macro, aren't you?

No RSTDISBL, no fun!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your quick reaction.

After a while i found that the assignment was before the main. I overlooked that -.-' After moving it in the main it worked.
Now i got the problem that the rest of the program doesn't now the variable Sensoren. (undeclared). If anyone knows a quick solution it would be great but i'm gone look at it too.

Edit:
I had Sensoren first as a global variable, because i use it multipel times in my program, but now it's a local variable so had to add it as a parameter in the functions

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rather than posting snippets here is a complete program that compiles without errors:

#include 
#include 

uint8_t N;
typedef struct {
    uint8_t Adres;
    uint8_t Adres_read;
    uint8_t Adres_write;
    uint8_t Adres_register;
}Sensor;

uint8_t value = 42;

int main(void) {
    Sensor *Sensoren =(Sensor*)malloc(N*sizeof(Sensor));
    Sensoren[0].Adres = value;
    Sensoren[0].Adres_write = value;
    Sensoren[0].Adres_read = value;
    Sensoren[0].Adres_register = value;
}

How does your test case differ?

Obviously in this Sensoren is an automatic to main() so is not externally visible. If I wanted that I'd put the typedef and an extern declaration of the pointer into a shared header with the instantiation of the pointer in this file. Something like:

// sensor.h
#ifndef SENSOR_H
#define SENSOR_H

typedef struct {
    uint8_t Adres;
    uint8_t Adres_read;
    uint8_t Adres_write;
    uint8_t Adres_register;
}Sensor;

extern Sensor *Sensoren;
#endif
// main.c
#include 
#include 
#include "sensor.h"

uint8_t N;
Sensor *Sensoren;

uint8_t value = 42;

int main(void) {
    Sensoren =(Sensor*)malloc(N*sizeof(Sensor));
    Sensoren[0].Adres = value;
    Sensoren[0].Adres_write = value;
    Sensoren[0].Adres_read = value;
    Sensoren[0].Adres_register = value;
}

Again this compiles without error. Another .c file could include sensor.h then refer to the Sensoren[] array.

(this is all pretty standard C in fact).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for for the reaction,

It has been a while sinds i have programmed in C so i had to dig it all up. But thanks for your help clawson.:D
I hadn't thought of using a .h file. I thought i make the whole program first and then split it in different files.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wel you don't HAVE to use a .h file but if you don't and Sensoren and the Sensor type need to be "seen" in two or more .c files you'll end retyping the struct typedef and the extern declaration in more than one place. .h simply allow you to keep one centrally maintainable copy that can be "seen" in more than one place. The key thing is not to litter the .h with "private" details. Just share what must be visible to all.

One way to look at this is to consider what you would give someone else to be able to use the the type and the array without exposing any more of your implementation than you have to, to them.

Also the chances are that you might put "N" as a #define in the shared header so everyone who uses the array knows the limit on the number of elements. In a C++ like way you might prefer to share this number as a const int rather than a #define. But in this case you have to be sure it will be optimised out and not instantiated by every .c file that #include's the shared header.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks for the explanation.
It sure is usefull to use Header files. I may change somethings in my program to split the code. To have a better overlook of what part of the program uses what variables.

Also, N is now just a integer, but i wanne change it, so a user can adjust the value with lookalike Scanf fucntion with a input from usart or something.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
After a while i found that the assignment was before the main

:)

Quote:
so had to add it as a parameter in the functions

But that is not different than allocating an auto variable:

int main(void){
auto Sensor Sensoren[N];
Sensoren[0].Address=value;
...

you do not need a malloc for that.
plzyv

No RSTDISBL, no fun!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another issue is why you are using malloc in an AVR.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm programming in C and so far as i know is this the easiest to make a variable array in C code were N can be changed in the program without many changes

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The question about why you would use malloc is more this, "why would you make a dynamic array rather than simply statically allocate the largest array you might need." The AVR is a small processor with very limited resources and malloc will use some on top of the actually allocated array. Given that the functionality of an AVR driven embedded device is severely constrained anyway, it is rarely advantageous to do dynamic allocation. Much better, most of the time, is to simply allocate an array big enough for the largest requirements and use only part of it most of the time. The fact is, if there's not room for the static array, there's not room for a dynamic one ( baring fancy reuse of memory which is difficult to do properly with malloc on such a constrained system anyway ).

Martin Jay McKee

As with most things in engineering, the answer is an unabashed, "It depends."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the tip. It is indeed more efficient to make an static array that has way more space then max needed then to make a dynamic array that can change of size.

I haven't thought of it that way. I thought that a dynamic array uses the same amount of memory as a static array with the same size, but it isn't.
Thank for the explanation.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I thought that a dynamic array uses the same amount of memory as a static array with the same size, but it isn't.

But the overhead is only 4 bytes.

The issue with using malloc() in an embedded system is more this:

If you just make one malloc() at the start of the code then (apart from that 4 byte overhead) it's virtually identical to pre-allocation. Where the problem with malloc() comes is when you keep using it over and over. A typical use for example is when you build a linked list. Each time you want to add data you malloc() space for a new object then link it into the "chain". When you start deleting earlier objects in the chain it effectively fragments the heap memory being used to malloc(). As malloc()/free() have no concept of garbage collection or movable allocations (until you get into virtual memory CPUs) then it's easy to fragment the heap. On a 4GB PC this doesn't really matter (and it's virtual anyway). On a 2K AVR it does.

The other real no-no is if you malloc() multiple copies of objects of more than one size. At least if they are all the same size then if an early one is deleted and then a later malloc() is made the chances are the space will just be re-used. But if you now try to allocate something larger it cannot re-use the "hole".

I'm not really advocating ever using malloc() in a 1..4K RAM micro but just playing devil's advocate to say that in the one case of one malloc() made at program start that is never free'd it probably doesn't matter how the allocation is done. But it's probably good practice to get out of the habit of using heap memory in RAM constrained systems - determine at design time your worst case memory usage and the pre-allocate it. That way you cannot run out at run time.

Oh and if you are going to use malloc() then always add assert()s that the returned pointer is not 0. 0 pointers are the spawn of Satan!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just to add another (avr-gcc-specific?) alternative:

If you don't want to fix the allocation size at compile time but instead leave it until runtime you can use alloca(). This is "automatic allocation" i.e. on the stack. Since main() never should return in an avr-gcc app, you can do such an allocation in main(). Other functions wanting variable size memory blocks allocated can also do their alloca() calls. The memory will be "released" when a function exits (just as "local variables allocated on the stack" are).

But do be aware that alloca()
- is not in any standard, and
- some consider it bad practice

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Related post.
ksfxp

No RSTDISBL, no fun!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

IIRC the most recent C standard allows an automatic array
to have its size defined when it goes in scope.
That would have much the same effect as alloca.
If necessary, one can assign its address to a global pointer.
In the case of alloca, the memory disappears when the function returns.
In the case of a variable sized aray, the usual scope rules apply.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
In the case of alloca, the memory disappears when the function returns.
In the case of a variable sized aray, the usual scope rules apply.

Is it that auto variable is freed at the moment when the function returns?
I thought that this is when the variable gets out of "curly braces" (scope).

int *ptr,getvar;
foo(void){
 {auto int vara;
 somefun(&vara);
 }
 ....
 {auto int varz;
 somefun(&varz);
 }
 //<--Is vara still available in here?
getvar=*ptr;
}

No RSTDISBL, no fun!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When it goes out of scope.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brutte wrote:
Quote:
In the case of alloca, the memory disappears when the function returns.
In the case of a variable sized aray, the usual scope rules apply.

Is it that auto variable is freed at the moment when the function returns?
Or sooner.
Quote:
I thought that this is when the variable gets out of "curly braces" (scope).
Any matched pair of syntactic curly braces
(the ones that define blocks), i.e. the usual scope rules.
Quote:

int *ptr,getvar;
foo(void){
 {auto int vara;
 somefun(&vara);
 }
 ....
 {auto int varz;
 somefun(&varz);
 }
 //<--Is vara still available in here?
getvar=*ptr;
}

vara disappears before the "....".

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
vara disappears before the "....".

:? Then the "alloca(sizeof(int))" would have had a significantly longer (at least !shorter) lifetime than "auto int vara" in the above example..
I always felt that using the addresses of auto variables is kind of living on the edge. One needs to remember where vara life ends (I am not sure if a gcc compiler can warn about getvar=*ptr;, or even worse, *ptr=getvar; !).
Otoh, in the above auto example only a shallow stack is needed (or it could even happen the varabc..z occupy one register). The alloca would require at least 26 levels for that and vara would still be accessible at the end (I hope).

OT: alloca() is not available in libc from gcc-arm-embedded (newlib).

No RSTDISBL, no fun!