It looks like you're not allocating space for your states in the machine past the first one.
StateMachine * create_state_machine(const char* name) {
StateMachine * temp;
temp = malloc(sizeof(struct StateMachine));
if (temp == NULL) {
exit(127);
}
temp->name = name;
temp->total_states = 0;
temp->states = malloc(sizeof(struct State)); // This bit here only allocates space for 1.
return temp;
}
You're probably better off putting an array of states of fixed size in the state machine struct. If that's not okay, you'll have to realloc and move the whole set around or allocate chunks and keep track of the current length, or make a linked list.
Incidentally, init, foo, and bar never get used.
Edit: What I'm suggesting looks like this:
#define MAX_STATES 128 // Pick something sensible.
typedef struct StateMachine {
const char * name;
int total_states;
State *states[MAX_STATES];
} StateMachine;
Answer from nmichaels on Stack OverflowIt looks like you're not allocating space for your states in the machine past the first one.
StateMachine * create_state_machine(const char* name) {
StateMachine * temp;
temp = malloc(sizeof(struct StateMachine));
if (temp == NULL) {
exit(127);
}
temp->name = name;
temp->total_states = 0;
temp->states = malloc(sizeof(struct State)); // This bit here only allocates space for 1.
return temp;
}
You're probably better off putting an array of states of fixed size in the state machine struct. If that's not okay, you'll have to realloc and move the whole set around or allocate chunks and keep track of the current length, or make a linked list.
Incidentally, init, foo, and bar never get used.
Edit: What I'm suggesting looks like this:
#define MAX_STATES 128 // Pick something sensible.
typedef struct StateMachine {
const char * name;
int total_states;
State *states[MAX_STATES];
} StateMachine;
It looks like you want to have a variable number of states in each state machine, but you are allocating the memory incorrectly. In create_state_machine, this line:
temp->states = malloc(sizeof(struct State));
Allocates a single State object, not an array of pointers (which is how you are using it).
There are two ways you could change this.
- Declare
statesasState states[<some-fixed-size>];but then you cant ever have more than a fixed number of states. - Add another member to indicate how much storage has been allocated for
states, so you can keep track of that as well as how much is used (which is whattotal_statesis being used for).
The later would look something like this:
#include <stdlib.h>
#include <string.h>
typedef struct
{
const char *name;
} State;
typedef struct
{
const char *name;
int total_states;
int states_capacity;
State *states;
} StateMachine;
StateMachine *create_state_machine(const char *name)
{
StateMachine *temp = malloc(sizeof(StateMachine));
memset(temp, 0, sizeof(*temp));
temp->name = name;
temp->states_capacity = 10;
temp->states = malloc(sizeof(State) * temp->states_capacity);
return temp;
}
State *add_state(StateMachine *machine, const char *name)
{
if (machine->total_states == machine->states_capacity)
{
// could grow in any fashion. here i double the size, could leave
// half the memory wasted though.
machine->states_capacity *= 2;
machine->states = realloc(
machine->states,
sizeof(State) * machine->states_capacity);
}
State *state = (machine->states + machine->total_states);
state->name = name;
machine->total_states++;
return state;
}
I have participated in many coding competitions but I'm unable to pass all the test cases just because of this problem. I don't know how to initialize an array with unknown size. I tried using
arr=malloc(size*sizeof(int));
But at the end it shows segmentation fault. Can someone explain why?
Struct unknown size
declare array without specified size - C++ Forum
Generating an array of unknown size
Initializing Array of structs - Arduino Stack Exchange
Hello everyone,
I have some code where I am transforming a height map into a mesh, the end result would be an array of vertices. However I am doing some optimisation to reduce the number of vertices as I'm creating it.
The problem being : I am adding vertices to the array before I know what the final number of vertices is. I don't want to allocate the maximum possible size and the reduce, since the platform has quite limited memory
My ideas : start with a medium sized array allocated, and then reallocate extra little pieces if the mesh increases passed that bound
Construct a linked list of vertices while I'm optimising the mesh, store the count. Allocate the flat array and then copy the linked list into that array.
I don't think just generating the linked list would work, because the platform has GL1.0 and you manually submit each triangle, and I'm worried about the performance that would come from cache misses so I think I would want the array to be contiguous, and increasing time to generate the mesh but saving time to render the mesh would be ideal.
But I'm not sure which is the most performant, or if I have some misunderstanding. apologies if this is a noob question, thank you for your time and help
led h_red = {0,0,255,0,300};
Here, you are defining a variable, and at the same time giving it an initial value. This is called an initialization.
led leds[LEDS];
Here you are defining an array. Since it is in global scope, and not explicitly initialized, it is implicitly initialized to all bytes zero.
leds[0] = {0,0,0,0,0};
Here, you are trying to give a value to an element of the array that has
already been defined previously. This is thus not an initialization,
but an assignment. Unlike initializations, assignments cannot exist
outside a function. If you want to assign initial values, you can do it
in setup().
Alternatively, you can initialize the array while you define it:
led leds[LEDS] = {
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 255, 0, 300}
};
I've upvoted @Edgar Bonet's answer, because it is correct.
I want to add some more examples and explanations though.
Key summary:
In C and C++, you can NOT have code logic outside of functions. The global context outside of functions is intended for declarations, definitions, and some initializations/constructors only. All code logic must be inside of a function. Code logic includes post-construction variable assignments, if statements, etc.
Examples:
1. NOT allowed:
Therefore, you can NOT do the following, since it attempts to do non-initializing assignments outside of all function scopes.
Notice also that in C++ (which Arduino is), you don't need to use typedef for structs either, so I've removed that from the struct definition. I'm also using the stdint.h types, which are considered safer and "best practice" for data types, as they specify the exact type size in bits. Use uint8_t in place of unsigned char, uint32_t instead of the Arduino Uno's unsigned long, and uint16_t instead of the Arduino Uno's unsigned int. Also, in C++ in particular, constexpr or enums are preferred over #define to set variable constants.
constexpr uint8_t NUM_LEDS = 3;
struct Led {
uint8_t current;
uint8_t start;
uint8_t target;
uint32_t startTime;
uint16_t duration;
};
Led leds[NUM_LEDS];
// NOT OK: Variable (re)assignments are NOT allowed outside of functions in
// C and C++.
leds[0] = {0, 0, 0, 0, 0};
leds[1] = {0, 0, 0, 0, 0};
leds[2] = {0, 0, 255, 0, 300};
void setup()
{
}
void loop()
{
}
2. IS allowed:
You CAN, however, have variable initializations outside of functions, so long as they occur at the same time as construction, so this is perfectly valid:
Led leds[NUM_LEDS];
// This form of aggregate initialization during construction is just fine in the
// global scope outside of all functions.
Led leds[NUM_LEDS] = {
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 255, 0, 300},
};
void setup()
{
}
void loop()
{
}
3. Also IS allowed:
Or, you can just move your reassignments into a function, such as setup():
Led leds[NUM_LEDS];
void setup()
{
// This variable (re)assignment is just fine since it's inside
// of a function.
leds[0] = {0, 0, 0, 0, 0};
leds[1] = {0, 0, 0, 0, 0};
leds[2] = {0, 0, 255, 0, 300};
}
void loop()
{
}
4. Full, runnable example on a PC:
Here's a full, runnable example on a PC, with printing to verify the contents of the struct were changed:
Run it online yourself on OnlineGDB here, or from my eRCaGuy_hello_world repo here: struct_array_initialization.cpp:
#include <stdint.h>
#include <stdio.h>
// Get the number of elements in a C-style array
#define ARRAY_LEN(array) (sizeof(array)/sizeof(array[0]))
constexpr uint8_t NUM_LEDS = 3;
struct Led {
uint8_t current;
uint8_t start;
uint8_t target;
uint32_t startTime;
uint16_t duration;
};
// To initialize once at construction. This form of aggregate initialization
// can be used anywhere: both inside and outside functions.
Led leds[NUM_LEDS] = {
{ 1, 2, 3, 4, 5},
{ 6, 7, 8, 9, 10},
{11, 12, 13, 14, 15},
};
// Print the full contents of an array of `Led` structs
void printLeds(const Led ledArrayIn[], size_t ledArrayLen)
{
for (size_t i = 0; i < ledArrayLen; i++)
{
printf("ledArrayIn[%lu]\n"
"current = %u\n"
"start = %u\n"
"target = %u\n"
"startTime = %u\n"
"duration = %u\n\n",
i,
ledArrayIn[i].current,
ledArrayIn[i].start,
ledArrayIn[i].target,
ledArrayIn[i].startTime,
ledArrayIn[i].duration);
}
}
int main()
{
printf("Hello World\n\n");
printLeds(leds, ARRAY_LEN(leds));
printf("==============\n\n");
// Do this to set or change the structs at any time AFTER construction!
// This variable (re)assignment is only allowed inside of a function, NOT
// in the global scope outside of all functions!
leds[0] = {10, 20, 30, 40, 50};
leds[1] = {60, 70, 80, 90, 100};
leds[2] = { 0, 0, 255, 0, 300};
printLeds(leds, ARRAY_LEN(leds));
return 0;
}
Sample output:
Hello World
ledArrayIn[0]
current = 1
start = 2
target = 3
startTime = 4
duration = 5
ledArrayIn[1]
current = 6
start = 7
target = 8
startTime = 9
duration = 10
ledArrayIn[2]
current = 11
start = 12
target = 13
startTime = 14
duration = 15
==============
ledArrayIn[0]
current = 10
start = 20
target = 30
startTime = 40
duration = 50
ledArrayIn[1]
current = 60
start = 70
target = 80
startTime = 90
duration = 100
ledArrayIn[2]
current = 0
start = 0
target = 255
startTime = 0
duration = 300
Other references:
- https://en.cppreference.com/w/cpp/language/aggregate_initialization
- [my answer] https://stackoverflow.com/questions/61240589/how-to-initialize-a-struct-to-0-in-c/61240590#61240590
I am also concerned if there can be situation that I free a pointer twice in my case
... and ...
Yes just I am more interested in cases when/if there can be for example freeing unallocated memory or freeing already freed memory ...
After a quick inspection it doesn't appear that you free memory more than once:
freestatements are only in thefreeArrayandmainmethods- Each
free(a->array[0].name);is different because each name is allocated using its own malloc free(a->array)is only called oncefreeArrayis only called oncefree(x.name);doesn't free the same memory asfree(a->array[0].name);becauseinsertArrayallocates new memory for each name
and how to avoid that
Something which can help (though not guarantee) is to assign NULL to the pointer after you pass it to free.
- It can help, because calling free on a previously-nulled pointer will harmlessly do nothing
- It's not a guarantee, because you might have more than one pointer pointing to the same memory
dmcr_code's comment below points out a bug. You wrote,
for(int i=0; i<a->used; i++)
{
free(a->array[0].name);
a->array[0].name=NULL;
}
This should be,
for(int i=0; i<a->used; i++)
{
free(a->array[i].name);
a->array[i].name=NULL;
}
Because you set a->array[0].name=NULL; after freeing it, you don't free it twice.
But, you did fail to free the memory associated with a->array[i].name for values of i larger than 0.
But then how do I protect against that - when array[i].name can contain random value and I try to free it?
To protect yourself:
- Either, don't let it contain a random value (e.g. ensure that it's either a valid pointer, or zero)
- Or, don't use it (e.g. ensure that your
a->usedlogic is correct so that you don't touch elements which you haven't used/initialized).
is memset in the initArray method fine for that?
memset is good:
- You could use calloc instead of malloc to avoid having to use memset as well
- You could use memset on the whole array at once instead of using memset on each element of the array
memset in initArray isn't enough. It's enough to begin with, but there's a realloc in insertArray. So to be good enough, you'd also need to use memset after realloc (to memset the as-yet-unused end of the newly-reallocated array; without using memset on the beginning of the reallocated array, which already contains valid/initialized/used elements).
the only unclear part that remains from your response is how to memset realloced array
Your current code in initArray says,
// Initialize all values of the array to 0
for(unsigned int i = 0; i<initialSize; i++)
{
memset(&a->array[i],0,sizeof(Student));
}
Another way to do that would be:
// Initialize all elements of the array at once: they are contiguous
memset(&a->array[0], 0, sizeof(Student) * initialSize);
The memset statement to add to insertArray would be:
if (a->used == a->size)
{
a->size *= 2;
a->array = (Student *)realloc(a->array, a->size * sizeof(Student));
// Initialize the last/new elements of the reallocated array
for(unsigned int i = a->used; i<a->size; i++)
{
memset(&a->array[i],0,sizeof(Student));
}
}
Or:
if (a->used == a->size)
{
a->size *= 2;
a->array = (Student *)realloc(a->array, a->size * sizeof(Student));
// Initialize the last/new elements of the reallocated array
memset(&a->array[a->used],0,sizeof(Student) * (a->size - a->used));
}
and this comment: "It's not a guarantee, because you might have more than one pointer pointing to the same memory " would be nice if you can address that too
This is safe:
void* foo = malloc(10);
free(foo);
// protect against freeing twice
foo = NULL;
// this is useless and strange, but harmless
free(foo);
This is not safe:
void* foo = malloc(10);
void* bar = foo;
free(foo);
// protect against freeing twice
foo = NULL;
// this is useless and strange, but harmless
free(foo);
// but this is dangerous, illegal, undefined, etc.
// because bar is now pointing to memory that has already been freed
free(bar);
I have 3 suggestions.
If you need to allocate memory and initialize it to zero use
calloc.
Usingcallocis better than usingmalloc + memsetSo change your
initArrayfunction like:void initArray(Array *a, size_t initialSize) { // Allocate initial space a->array = (Student *)calloc(initialSize , sizeof(Student)); a->used = 0; // no elements used a->size = initialSize; // available nr of elements }Single character variable names are very bad. Use proper names for variables and follow naming conventions.
In your code you are only creating and adding 3 objects. But you are trying to print the details of 4th object. (Array index is starting from zero, so index 3 means 4th object)
printf("%d\n", a.array[3].ID); printf("%s\n", a.array[3].name);