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 Overflow
Top answer
1 of 5
13

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;
2 of 5
12

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.

  1. Declare states as State states[<some-fixed-size>]; but then you cant ever have more than a fixed number of states.
  2. 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 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;
}
🌐
Reddit
reddit.com › r/cprogramming › how to create an array with unknown size?
r/cprogramming on Reddit: How to Create an array with unknown size?
March 11, 2020 -

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?

Discussions

Struct unknown size
Hello, I’m currently working on an inventory system, I need to make an Array out of my struct, this is the code of the struct: and this is the code of the array: I’m new to c++ so It’s probably not the cleanest code you’ve ever seen, the problem is, I get this error: And no matter what ... More on forums.unrealengine.com
🌐 forums.unrealengine.com
1
1
March 2, 2021
declare array without specified size - C++ Forum
Technically, it's impossible to create an array of unknown size. In reality, it's possible to create an array, and resize it when necessary. More on cplusplus.com
🌐 cplusplus.com
Generating an array of unknown size
You my friend, are looking for a linked list. More on reddit.com
🌐 r/C_Programming
22
2
May 7, 2021
Initializing Array of structs - Arduino Stack Exchange
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. More on arduino.stackexchange.com
🌐 arduino.stackexchange.com
December 20, 2020
🌐
Arduino Forum
forum.arduino.cc › projects › programming
Array problem : type containing an unknown-size array is not allowed - Programming - Arduino Forum
May 7, 2017 - I need to create a structure like sort of tree. But I'm stuck at a point. Here is the code. typedef struct { String Name; uint8_t Age; uint8_t Toys; } Child; typedef struct { String Name; uint8_t Age; Child Children[]; } Parent; Parent Parents[] = { { "Parent 1", 40, { {"Child 1", 2} , {"Child 2", 5} , {"Child 3", 10} , } }, { "Parent 2", 45, { {"Child 1", 4} } } }; void PrintAllInfo() { uint8_t parentsCount = sizeof(Parents);//may not return 2 fo...
🌐
GeeksforGeeks
geeksforgeeks.org › c language › flexible-array-members-structure-c
Flexible Array Members in a structure in C - GeeksforGeeks
August 20, 2024 - The structure must contain at least one more named member in addition to the flexible array member. ... In the above code snippet, the size i.e. length of array "stud_name" isn't fixed and is a FAM.
🌐
Shivankaul
shivankaul.com › blog › zero-length-arrays
Zero-length arrays in C have to go at the end of the struct
July 3, 2017 - If instead of data[0] the original programmer had written data[] (as defined by C99), then when I moved the member to any place other than the last, I would have gotten the error field has incomplete type (the compiler thinks you’re trying to initialize a normal array). However, as the syntax variable_name[0] exercises a language extension (which at this point exists for backwards compatibility), the only way to get GCC to grumble was by passing in -pedantic to get a measly warning about how ISO C forbids zero-size arrays.
🌐
Medium
medium.com › @zgza778 › c-arrays-why-unknown-sizes-are-allowed-4265aebbf50b
C Arrays: Why Unknown Sizes Are Allowed | by Phoebe Theresa Peters | Medium
April 4, 2025 - However, you can create a new array of a larger size and copy the elements from the old array to the new one. There are also dynamic alternatives like List which provides more flexibility when the size isn’t known in advance. C Arrays: Why Unknown Sizes Are Allowed This article explores a nuanced exception to the fixed-size rule. C arrays are widely used in various programming scenarios. They are particularly useful when dealing with collections of data where the size is known in advance.
🌐
Cplusplus
cplusplus.com › forum › beginner › 7961
declare array without specified size - C++ Forum
Technically, it's impossible to create an array of unknown size. In reality, it's possible to create an array, and resize it when necessary.
Find elsewhere
🌐
Reddit
reddit.com › r/c_programming › generating an array of unknown size
r/C_Programming on Reddit: Generating an array of unknown size
May 7, 2021 -

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

Top answer
1 of 2
10
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}
};
2 of 2
1

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:

  1. https://en.cppreference.com/w/cpp/language/aggregate_initialization
  2. [my answer] https://stackoverflow.com/questions/61240589/how-to-initialize-a-struct-to-0-in-c/61240590#61240590
🌐
Archlinux
copyprogramming.com › t › making-struct-with-unknown-size-array-with-memory-location
Making Struct With Unknown Size Array With Memory Location - CopyProgramming
does not give the option to initialize an array if his size is not an constant value, and if I initialize, If this is a variable based on user input then you must create the array in heap memory, It provides you a good level of abstraction and item are stored in contingent memory like an array., In compilation, it doesn't determine the size of the array., It realocate the memory in stack to the array in run. ... Is this the correct way to Allocate Memory For An Array of structs?, *array; int i; //Allocate memory for rows (to store 'size' many pointers to 'date' struct data, type) array = malloc(size*sizeof(date*)); //For-loop to allocate memory for columns (to store, 'size' many integers, and initialize them to zero) for (i=0; i<size; i++) { array, with the size of the pointer to the date struct instead of the actual size of the date struct.
🌐
YouTube
youtube.com › watch
- YouTube
Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube.
Published   May 28, 2022
🌐
Arm Community
community.arm.com › developer › tools-software › tools › f › keil-forum › 41403 › empty-arrays-in-nested-structures
Challenge Validation
July 16, 2019 - The Arm tools range offers two software development families that provide you with all the necessary tools for every stage of your software development workflow.
🌐
GNU
gcc.gnu.org › onlinedocs › gcc-4.7.1 › gcc › Zero-Length.html
Zero Length - Using the GNU Compiler Collection (GCC)
Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure which is really a header for a variable-length object: struct line { int length; char contents[0]; }; struct line *thisline = (struct line *) malloc (sizeof (struct line) + this_length); ...
🌐
HowStuffWorks
computer.howstuffworks.com › tech › computer software › programming
Pointers to Structures - The Basics of C Programming | HowStuffWorks
March 8, 2023 - Using the array of pointers allows the array to take up minimal space until the actual records are allocated with malloc statements. The code below simply allocates one record, places a value in it, and disposes of the record to demonstrate the process: typedef struct { char s1[81]; char s2[81]; char s3[81]; } Rec; Rec *a[10]; a[0] = (Rec *)malloc(sizeof(Rec)); strcpy(a[0]->s1, "hello"); free(a[0]);
🌐
GNU
gcc.gnu.org › onlinedocs › gcc-3.2.3 › gcc › Zero-Length.html
Arrays of Length Zero
May 11, 2022 - Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure which is really a header for a variable-length object: struct line { int length; char contents[0]; }; struct line *thisline = (struct line *) malloc (sizeof (struct line) + this_length); ...
Top answer
1 of 4
8

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:

  • free statements are only in the freeArray and main methods
  • Each free(a->array[0].name); is different because each name is allocated using its own malloc
  • free(a->array) is only called once
  • freeArray is only called once
  • free(x.name); doesn't free the same memory as free(a->array[0].name); because insertArray allocates 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->used logic 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);
2 of 4
5

I have 3 suggestions.

  • If you need to allocate memory and initialize it to zero use calloc.
    Using calloc is better than using malloc + memset

    So change your initArray function 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);   
    
🌐
Javaer101
javaer101.com › en › article › 13667105.html
C++: static array inside class having unknown size - Javaer101
You only have a declaration for the static field at this point. You never use those arrays and the compiler is permissive... it won't complain. If you want to use them however, you'll need a definition. If you omit the size there, you'll get similar error messages you saw before.
🌐
Xspdf
xspdf.com › resolution › 53773665.html
Xspdf
Powerful PDF API for developers. Generate, convert, merge, split, compress, protect and extract PDFs programmatically. RESTful API with simple integration.
🌐
AstroDeck
xspdf.com › resolution › 50770133.html
xspdf — PDF Generation & Processing API for Developers | xspdf
Powerful PDF API for developers. Generate, convert, merge, split, compress, protect and extract PDFs programmatically. RESTful API with simple integration.