I\'ve been trying to wrap my head around this the whole day...
Basically, I have a struct called State that has a name and another one called StateMachine with a name, a
State ** states;
will create an array of state arrays.
I haven't read through the whole solution truthfully (gotta run), but you mentioned wanting an array of states - did you possibly want to do:
State* states
or
State states[size];
instead? Just food for thought, chances are it wasn't your problem since I didn't fully read it :p
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.
states
as State states[<some-fixed-size>];
but then you cant ever have more than a fixed number of states.states
, so you can keep track of that as well as how much is used (which is what total_states
is 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;
}
You're doing a conceptual error:
State ** states;
It's true that you can consider states like an array of pointer to State object, but you are allocating space for just one state. When you do:
state_machine->states[state_machine->total_states]= temp;
you are doing something wrong if total_states is greater than zero because you are pointing to memory segments that are not been allocated (I'm wondering why you don't get a SEGFAULT). To store a dynamic number of State this way you need a linked list, or to call realloc every state you add(but that's not a good idea). The memory you are allocating with different malloc calls isn't continuous.
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;
Inside of your add_state function:
temp = malloc(sizeof(struct StateMachine));
should be
temp = malloc(sizeof(struct State));
However, even when this is changed, I still get the proper output:
--> [0] state: Init
--> [1] state: Foo
--> [2] state: Bar
Perhaps there's nothing wrong with your code. I'm using gcc version 4.4.3