C Struct array member without specific length - c

I have encountered this piece of code:
struct test
{
uint32 num_fields;
char array_field [];
};
How can I understand array_field? Is this a gcc extension for the C language?

It's a C99 feature, called flexible array member which is typically used to create a variable length array.
It can only be specified as the last member of a struct without specifying the size (as in array_field [];).
For example, you can do the following and the member arr will have 5 bytes allocated for it:
struct flexi_example
{
int data;
char arr[];
};
struct flexi_example *obj;
obj = malloc(sizeof (struct flexi_example) + 5);
Its pros/cons discussed here:
Flexible array members in C - bad?

Such structures are usually allocated on the heap with a calculated size, with code such as the following:
#include <stddef.h>
struct test * test_new(uint32 num_fields)
{
size_t sizeBeforeArray = offsetof(struct test, array_field);
size_t sizeOfArray = num_fields * sizeof(char);
struct test * ret = malloc(sizeBeforeArray + sizeOfArray);
if(NULL != ret)
{
ret->num_fields = num_fields;
}
return ret;
}

Related

Freeing up struct created with malloc who's member also had a malloc

Let's say I have a struct for implementing vectors in C like this:
struct cvector {
unsigned int size; // indicates number of element in the vector
unsigned int capacity; // indicates length of the array
int* data; // array to store the actual data
};
typedef struct cvector* cvector;
Then I create this vector like this:
cvector cvector_create() {
cvector retval = (cvector)malloc(sizeof(struct cvector));
retval->capacity = 8;
retval->size = 0;
retval->data = (int*)malloc(retval->capacity * sizeof(int));
return retval;
}
I use malloc for both allocating memory for the struct and for allocating memory for the internal int array.
For freeing up my cvector I use this:
void cvector_free(cvector vector) {
free(vector);
}
My question is, do I need to free the internal int array as well separately like this: free(vector->data) or is freeing up only the struct is enough?
Yes, you need to free also vector->data, the rule is: one call to free per each call to malloc
if you are under C99, you can use flexible array members:
struct cvector {
unsigned int size; // indicates number of element in the vector
unsigned int capacity; // indicates length of the array
int data[]; // array to store the actual data
};
Notice that int data[]; must be the last member of the struct.
Then, you reserve space in this way:
cvector cvector_create() {
cvector retval = malloc(sizeof(struct cvector) + (sizeof(int) * 8));
retval->capacity = 8;
retval->size = 0;
return retval;
}
Now, calling free(vector) is enough since vector and vector->data are on the same block.

General-purpose char buffer used as array of structs with flexible array member

You can't have arrays of structures with flexible array members.
This is the TL;DR of this question. And thinking about it, it makes perfect sense.
However, may one simulate an array of structures with flexible array member - let's call them swfam - of fixed size as below :
#include <assert.h>
#include <stdlib.h>
typedef struct {
int foo;
float bar[];
} swfam_t; // struct with FAM
typedef struct { // this one also has a FAM but we could have used a char array instead
size_t size, // element count in substruct
count; // element count in this struct
char data[];
} swfam_array_t;
#define sizeof_swfam(size) (sizeof(swfam_t) + (size_t)(size) * sizeof(float))
swfam_array_t *swfam_array_alloc(size_t size, size_t count) {
swfam_array_t *a = malloc(sizeof(swfam_array_t) + count * sizeof_swfam(size));
if (a) {
a->size = size;
a->count = count;
}
return a;
}
size_t swfam_array_index(swfam_array_t *a, size_t index) {
assert(index < a->count && "index out of bounds");
return index * sizeof_swfam(a->size);
}
swfam_t *swfam_array_at(swfam_array_t *a, size_t index) {
return (swfam_t *)&a->data[swfam_array_index(a, index)];
}
int main(int argc, char *argv[]) {
swfam_array_t *a = swfam_array_alloc(100, 1000);
assert(a && "allocation failed");
swfam_t *s = swfam_array_at(a, 42);
s->foo = -18; // do random stuff..
for (int i = 0; i < 1000; ++i)
s->bar[i] = (i * 3.141592f) / s->foo;
free(a);
return 0;
}
Is the trick valid C99 / C11 ? Am I lurking towards undefined behaviour ?
One way to do this would be to use a pointer member instead of a flexible array. You would then have to manually allocate its size via malloc() et. al. [] is typically used only when the array is initialized on declaration, which is not possible with struct, which is essentially a definition, not a declaration. The ability to immediately declare an instance of the struct type does not change the nature of the definition, it's just for convenience.
typedef struct {
int foo;
float* bar; } swfam_t; // struct with FAM

Is it possible to set the size of an array within structure during runtime?

I have a structure as below:
struct Query {
int pages[];
int currentpage;
};
I was wondering if it was possible to set the size of this array after creating the structure.
Query new = malloc(sizeof(struct Query));
After this, I will perform some calculations which will then tell me the size that pages[] needs to be. If pages[] needed to be of size 4, how can I set it as such?
In C99 you can use Flexible array members:
struct Query {
int currentpage;
int pages[]; /* Must be the last member */
};
struct Query *new = malloc(sizeof(struct Query) + sizeof(int) * 4);
Change the type of pages member to pointer.
struct Query {
int *pages;
int currentpage;
};
struct Query *test = malloc(sizeof(struct Query));
if (test != NULL)
{
//your calculations
test->pages = malloc(result_of_your_calcs);
if (test->pages != NULL)
{
// YOUR STUFF
}
else
{
// ERROR
}
}
else
{
// ERROR
}
When you'll free your struct, you have to do that on the contrary.
free(test->pages);
free(test);
You can use a Flexible array member (details in #AlterMann's answer) (C99+), or a Zero length array (GNU C).
Quoting from https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html,
Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure that 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);
thisline->length = this_length;
For standard C90, the linked site mentions
In ISO C90, you would have to give contents a length of 1, which means either you waste space or complicate the argument to malloc.
This means that for the code to work in standard C90/C89, char contents[0]; should be char contents[1];.
Declare it as pointer and use malloc afterwards
struct Query {
int * pages;
int currentpage;
};
. . .
struct Query obj;
obj.pages = malloc(n * sizeof(int)); // n is the length you want
The best solution would be to use pointers to int instead of array.
You will need to change :
int pages[];
to :
int *pages;
and then dynamically allocate it like this :
Query *new = malloc(sizeof(struct Query));
if (new == NULL)
printf ("Error\n");
else
{
new->pages = malloc(4*sizeof(int));
if (new->pages == NULL)
printf ("Error\n");
}
Otherwise if you want to keep your format, you will use C99 mode. Declare pages as the last member of your struct, like this :
struct Query {
int currentpage;
int pages[];
};
and then do :
Query *new = malloc(sizeof(struct Query) + 4*sizeof(int));

The usage of `sizeof` in C

I am reading the source code of redis.
Here is the code:
typedef char *sds;
struct sdshdr {
unsigned int len;
unsigned int free;
char buf[];
};
static inline size_t sdslen(const sds s) {
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
return sh->len;
}
static inline size_t sdsavail(const sds s) {
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
return sh->free;
}
About this code, I have some issue:
Why is the output of sizeof(struct sdshdr) 8? Why is char buf[] not included?
I can't understand the functions size_t sdslen and sdsavail. Why do struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));?
char buf[] hasn't allocated any memory so it doesn't take up space therefore acting as a flexible array therefore 2 int datatype ends up taking 4+4 = 8 bytes.
in size_t, the variable passed is s that belongs to *sds which is a typedef of a char
This leads to the implementation of this code in memory.
if (init) {
sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
} else {
sh = zcalloc(sizeof(struct sdshdr)+initlen+1);
}
if (sh == NULL) return NULL;
sh->len = initlen;
sh->free = 0;
if (initlen && init)
memcpy(sh->buf, init, initlen);
sh->buf[initlen] = '\0';
return (char*)sh->buf;
}
which stores memory space equal to the sh sdshdr struct.
The 0-sized array has no size, it's declared length is 0. This is a flexible array member; it can only appear at the end of a struct.
That initialization sets sh to point at memory computed by taking the value of s, a char *, and subtracting the size of the sds header. In other words, from a pointer to the first character of a string (the flexible array member) we compute a pointer to the header itself so we can get at the length.

array of type void

plain C have nice feature - void type pointers, which can be used as pointer to any data type.
But, assume I have following struct:
struct token {
int type;
void *value;
};
where value field may point to char array, or to int, or something else.
So when allocating new instance of this struct, I need:
1) allocate memory for this struct;
2) allocate memory for value and assign it to value field.
My question is - is there ways to declare "array of type void", which can be casted to any another type like void pointer?
All I want is to use "flexible member array" (described in 6.7.2.1 of C99 standard) with ability to casting to any type.
Something like this:
struct token {
int type;
void value[];
};
struct token *p = malloc(sizeof(struct token) + value_size);
memcpy(p->value, val, value_size);
...
char *ptr = token->value;
I suppose declaring token->value as char or int array and casting to needed type later will do this work, but can be very confusing for someone who will read this code later.
Well, sort of, but it's probably not something you want:
struct token {
// your fields
size_t item_size;
size_t length
};
struct token *make_token(/* your arguments */, size_t item_size, size_t length)
{
struct token *t = malloc(sizeof *t + item_size * length);
if(t == NULL) return NULL;
t->item_size = item_size;
t->length = length;
// rest of initialization
}
The following macro can be used to index your data (assuming x is a struct token *):
#define idx(x, i, t) *(t *)(i < x->length ? sizeof(t) == x->item_size ?
(void *)(((char *)x[1]) + x->item_size * i)
: NULL : NULL)
And, if you like, the following macro can wrap your make_token function to make it a little more intuitive (or more hackish, if you think about it that way):
#define make_token(/* args */, t, l) (make_token)(/* args */, sizeof(t), l)
Usage:
struct token *p = make_token(/* args */, int, 5); // allocates space for 5 ints
...
idx(p, 2, int) = 10;
Expanding on AShelly's answer you can do this;
/** A buffer structure containing count entries of the given size. */
typedef struct {
size_t size;
int count;
void *buf;
} buffer_t;
/** Allocate a new buffer_t with "count" entries of "size" size. */
buffer_t *buffer_new(size_t size, int count)
{
buffer_t *p = malloc(offsetof(buffer_t, buf) + count*size);
if (p) {
p->size = size;
p->count = count;
}
return p;
}
Note the use of "offsetof()" instead of "sizeof()" when allocating the memory to avoid wasting the "void *buf;" field size. The type of "buf" doesn't matter much, but using "void *" means it will align the "buf" field in the struct optimally for a pointer, adding padding before it if required. This usually gives better memory alignment for the entries, particularly if they are at least as big as a pointer.
Accessing the entries in the buffer looks like this;
/** Get a pointer to the i'th entry. */
void *buffer_get(buffer_t *t, int i)
{
return &t->buf + i * t->size;
}
Note the extra address-of operator to get the address of the "buf" field as the starting point for the allocated entry memory.
I would probably do this:
struct token {
int type;
void *value;
};
struct token p;
p.value = malloc(value_size);
p.value[0] = something;
p.value[1] = something;
...
edit, actually you have to typecast those p.value[index] = somethings. And/or use a union to not have to typecast.
You can't have an array of 'void' items, but you should be able to do something like what you want, as long as you know value_size when you do the malloc. But it won't be pretty.
struct token {
int type;
void *value;
};
value_size = sizeof(type)*item_count;
struct token *p = malloc(sizeof(struct token) + value_size);
//can't do memcpy: memcpy(p->value, val, value_size);
//do this instead
type* p = (type*)&(p->value);
type* end = p+item_count;
while (p<end) { *p++ = someItem; }
Note that you need an extra address-of operator when you want to get the extra storage.
type *ptr = (type*)&(token->value);
This will 'waste' sizeof(void*) bytes, and the original type of value doesn't really matter, so you may as well use a smaller item. I'd probably typedef char placeholder; and make value that type.
following structure can help you.
struct clib_object_t {
void* raw_data;
size_t size;
};
struct clib_object_t*
new_clib_object(void *inObject, size_t obj_size) {
struct clib_object_t* tmp = (struct clib_object_t*)malloc(sizeof(struct clib_object_t));
if ( ! tmp )
return (struct clib_object_t*)0;
tmp->size = obj_size;
tmp->raw_data = (void*)malloc(obj_size);
if ( !tmp->raw_data ) {
free ( tmp );
return (struct clib_object_t*)0;
}
memcpy ( tmp->raw_data, inObject, obj_size);
return tmp;
}
clib_error
get_raw_clib_object ( struct clib_object_t *inObject, void**elem) {
*elem = (void*)malloc(inObject->size);
if ( ! *elem )
return CLIB_ELEMENT_RETURN_ERROR;
memcpy ( *elem, inObject->raw_data, inObject->size );
return CLIB_ERROR_SUCCESS;
}
More Details : clibutils
Array of type void is not supporting in c/c++.
Example like:
int main() {
void alexa[]; // error: declaration of ‘alexa’ as array of void
return 0;
}
Array of void pointer is supported in c/c++.
Example below:
int main(int argc, char argv*[])
{
void *alexa[100]; // Compiled successfully
return 0;
}

Resources