Handling arrays of C structs - c

I have a C
struct of the form :
#define RGB_TYPE 1
#define YUV_TYPE 2
#define MAX_LIST 20
typedef struct
{
uint16_t a[2];
uint8_t b;
float_t c;
} mystruct;
I have an array of mystruct like this
mystruct MyStructList[MAX_LIST]= {
{{100, 200}, RGB_TYPE, 25.0},
{{200, 400}, RGB_TYPE,25.0},
{{300,600} ,YUV_TYPE ,30.0},
{{400,600},YUV_TYPE, 30.0}
};
In my code I do the following ;
mystruct config;
int i = 0;
.....
for(i=0;i<4;i++)
{
config = MyStructList[i];
/* further processing on config */
some_func(i,&config);
}
int some_func(int x, mystruct* pstruct );
{
/* using pstruct values and storing them in internal arrays */
}
Is this sort of struct copy and handling valid ?
I am using mingw gcc

It looks OK, but note that config = MyStructList[i]; makes a shallow copy of the struct. If you want to operate on the original array, mystruct should be a pointer that takes the address of MyStructList[i].
For example:
for(i=0;i<4;i++)
{
mystruct * config = &MyStructList[i];
some_func(i, config);
}

Instead of saying config = MyStructList[i]; you should allocate the number of elements needed by using malloc. For example, in the loop body, you should say
mystruct * config = ( mystruct *) malloc ( i * sizeof ( mystruct ) );
some_func ( i, config ); // You do not have to use address because config is a pointer type now
free ( config );

This kind of copy is valid. It might not be efficient, you could just use a pointer to the original struct when calling some_func(). Then in some_func you store a copy of it's values in internal arrays.

Related

C struct with array size determined at compile time

How does one build a struct with an array that can be set differently for each struct, ideally by a parameter? The application being a single data type that supports arrays of different, but fixed lengths
My attempt looks somehting like this, which obviously didnt compile:
struct Data_struct(n)
{
int xData[n];
int test;
};
The only method available is to use a flexible array member.
struct Data_struct {
int test;
int xData[];
};
You would then allocate space for this using malloc():
int n = 4;
struct Data_struct *s = malloc(sizeof(struct Data_struct) + n * sizeof(int));
Note that we had to explicitly allocate additional space for the flexible array.
You can dynamically allocate the array
struct Data_struct
{
int * xData;
int test;
};
....
s.xData = calloc(size, sizeof(int))
and remember to free xData when finished
Normally you would define a variable length array at the end of the struct, and then fix up the size at run-time, e.g.
typedef struct
{
int test;
int xData[1];
} Data_struct;
To allocate a struct such as this with a size of n for xData you'd do soemthing like this:
Data_struct * s = malloc(sizeof(Data_struct) + (n - 1) * sizeof(int));
One might call this ugly but here goes. Use a #define
#define foo(n) struct Data_struct##n { int test; int xData[n]; }
foo(20);
struct Data_struct20 abc;
The foo(20) defines a structure with n = 20 characters.
You could use another #define for the allocation of space if you wish.

return static structure array pointer with get()

I have a file in my project that has a local structure array defined like MyStruct_t myStruct[SIZE] which I can use well within that module. Now I would like to make it accessible to a different code module, so I came up with a function:
MyStruct_t *GetStruct(void) {
return myStruct;
}
But when I call this from my different module, I get an error expression must be a modifiable lvalue. My caller looks like:
void myFunc(void) {
MyStruct_t locStruct;
locStruct = GetStruct();
}
How can I do this best?
GetStruct returns a pointer to myStruct[SIZE] element, not a MyStruct_t. Unless you really need a copy, make locStruct a pointer, like this:
MyStruct_t *locStruct = GetStruct();
note that locStruct is an array of MyStruct_t, of size SIZE.
If you do want to make a copy, dereference GetStruct()'s result:
MyStruct_t locStruct = *GetStruct();
This would produce a copy of the initial element of myStruct array.
Since GetStruct does not provide additional services except accessing myStruct, you might as well make myStruct global (extern) instead of static.
Finally, you could change GetStruct to access a specific element. This would also take care of detecting overruns - i.e. attempts at getting an element past the SIZE or at a negative index:
bool GetStruct(int index, MyStruct_t *ptr) {
if (index < 0 || index >= SIZE) {
return false;
}
*ptr = myStruct[index];
return true;
}
Now the call of GetStruct() would look like this:
MyStruct_t locStruct;
if (GetStruct(5, &locStruct)) {
// All good
} else {
// Error
}
For example you can do the following way
void myFunc( void )
{
MyStruct_t locStruct[SIZE];
MyStruct_t *p = GetStruct();
memcpy( locStruct, p, SIZE * sizeof( MyStruct_t ) );
}
Or it might be enough to have a pointer to the first element of the array
void myFunc( void )
{
MyStruct_t *locStruct = GetStruct();
}
In this case the syntax for accessing elements of the array will be the same as for example locStruct[i]
GetStruct returns a pointer, so your locStruct variable should be a pointer, too.
void myFunc(void) {
MyStruct_t *locStruct;
locStruct = GetStruct();
}
If myStruct is global in the other module, then you might be looking for the extern keyword. Just put this in the other module:
extern MyStruct_t myStruct[];
(I've assumed MyStruct_t is a typedefed name. Otherwise you'd need to put the keyword struct before it, of course.)
This also requires access to the declaration of MyStruct. Put that in a header file and include it in both modules.
Here's a simple example:
// main.h ------------------------------------------------
typedef struct {
int a, b, c;
} AStruct;
// func.h ------------------------------------------------
void func(void);
// main.c ------------------------------------------------
#include <stdio.h>
#include "main.h"
#include "func.h"
AStruct as[100];
int main(void) {
func();
printf("%d,%d,%d\n", as[0].a, as[0].b, as[0].c);
return 0;
}
// func.c ------------------------------------------------
#include "main.h"
#include "func.h"
extern AStruct as[];
void func(void) {
as[0].a = 1;
as[0].b = 2;
as[0].c = 3;
}

Use a struct in a header file [ C - Linux ]

I tried to use an external struct but when I compile my c code I obtained this message:
subscripted value is neither array nor pointer nor vector.
Why?
messaggio.h
struct Request {
struct {
u_int data_len;
float *data_val;
} data;
bool_t last;
};
typedef struct Request Request;
main.c
#include "messaggio.h"
int main(void){
struct Request x;
x.data[0] = 4.6;
printf("%f\n",x.data[0]);
return 0;
}
The x.data is a struct, so you cannot use [] with it. Maybe you want x.data.data_val[0].
Try this code:
struct Request x;
x.data.data_len = 5; // initialize the length, use any value you need
x.data.data_val = (float *) malloc(x.data.data_len * sizeof(float));
x.data.data_val[0] = 4.6
x.data is a structure and not an array.
Use x.data.data_val[0] if that is what you are trying to access. However, you have not allocated any memory for data_val. I believe you are trying to assign a number to data_len and will need to allocate the memory to hold data_len values in data_val.
The type of struct Request#data is an anonymous struct { u_int, float } and not an array. Thus you can't use the [] operator on it.
You probably wanted to do:
x.data.data_val[0]

Variable-length array in file scope?

I have this code for example.
#include <stdlib.h>
#include <stdio.h>
#define array_size 3
typedef struct {
int array[array_size];
} TEST;
void printout(TEST *p, int element) {
printf("element: %i\n", p->array[element]);
}
int main(void) {
TEST *p;
p = malloc(sizeof(TEST));
p->array[0] = 5;
printout(p, 0);
return 0;
}
But I'd like to assign "array_size" based on user input.
If I try to do so, the compiler says "variably modified ‘array_size’ at file scope". So, am I right that the only way to do what I want is to move everything to main()..?
It works just fine, but keeping structs and functions declarations in file scope seems, you know, neat.
The simplest approach is to just allocate the memory dynamically:
typedef struct {
int *array;
size_t size;
} TEST;
int main() {
size_t elem_count = /* from user input */
TEST p;
p->array = malloc(elem_count * sizeof int);
if(!p->array)
return -1;
p->size = elem_count;
/* ... */
free(p->array);
}
You can indeed not define a variable length array at file scope, you can however define a pointer at file scope and malloc it, just define a global pointer int* p = NULL; (lose the whole TEST stuff) and p = malloc(sizeof(int) * input_size); simply access with p[x].
For completeness, you can also use the so called flexible array member defined in C99:
From ISO/IEC 9899:1999, Section 6.7.2.1, paragraph 16:
As a special case, the last element of a structure with more than one
named member may have an incomplete array type; this is called a
flexible array member.
typedef struct {
other_type other_data
int array[];
} TEST;
...
TEST *p = malloc(sizeof(TEST) + sizeof(int) * input_size);
Though note that this is limited to a single member, you could make an array of structs if you would otherwise have multiple arrays of different types but the same length.
This was originally intended mostly for data with headers such as ofter encountered in file and/or network I/O.

Return a struct from a function containg a static array in C

struct MyStruct
{
int i;
double arr[10];
};
struct MyStruct func()
{
};
When returned from the function, will be fully copied to a local variable?
struct Mystruct ms = func();
Yes you can, the structure will be fully copied.
Yes, if func() returns a variable of type Mystruct.
The correct way to do this:
void func(struct MyStruct* by_ref);
int main()
{
struct MyStruct ms;
func(&ms);
}
This won't upload a bombastic struct on the stack, nor will you get issues with static variables. Returning a pointer to a static variable is very bad for the following reasons:
It breaks private encaptulation. Very bad program design.
A multi-threaded program doing this gets vulnerable.
Pure bugs, as in this example:
static uint8 static_str[6];
uint8* func(const uint8 str[6])
{
uint8 i;
for(i=0; i<6; i++)
{
static_str[i] = str[i];
}
return static_str;
}
int main()
{
print_strings(func(“hello”), func(“world”));
}
The output from a function printing the two strings will be either “hello hello” or “world world” (depending on the order of evaluation of function parameters).
You have no return value so in any case you need to set that. Furthermore, it is better to use a pointer:
struct MyStruct* func()
{
struct MyStruct *pMyStruct=calloc(1,sizeof(struct MyStruct));
/* fill struct */
return pMyStruct;
};

Resources