Access fields of a struct dynamically - c

I have defined these 2 structs:
#define MAP_SIZE 5
typedef struct battle_cell {
int status_a;
int status_b;
int ship_a;
int ship_b;
} battle_cell;
struct battlemap {
battle_cell cell[MAP_SIZE][MAP_SIZE];
int progress_a;
int progress_b;
};
After the initalization of the map and all the other variables with zeros:
for (i = 0; i < MAP_SIZE; i++) {
for (j = 0; j < MAP_SIZE; j++) {
map->cell[i][j].status_a = 0;
map->cell[i][j].status_b = 0;
map->cell[i][j].ship_a = 0;
map->cell[i][j].ship_b = 0;
}
}
map->progress_a = 0;
map->progress_b = 0;
There is a point that I have to check the ship_a and ship_b values that live in each cell, something like that (the logic is a bit more complex than this iteration):
for (i = posXB; i < posXB + SHIP_SIZE; i++) {
map->cell[posYB][i].ship_b = 1;
}
I need to do exactly the same for the ship_a variable. So, I have to duplicate quite a big chunk of code because I am not able to find a way to get the field within the struct dynamically. For example, I could define a function:
void cell_iteration (battlemap *map, int pos, int pos_y, int ship_size, /* field_parameter/pointer */) {
int i;
for (i = pos; i < pos + ship_size; i++) {
map->cell[pos_y][i].ship_b = 1; // use the field_parameter/pointer instead of ship_b
}
}
Is there an elegant way to do something like that?
UPDATE
Just a clarification. The structs can definitely be simplified, but this is not my question. I 've just tried to create an example :)

Instead if ship_a and ship_b int the first struct, you can declare int ship[2] an array of 2 int.

Related

How to loop over variable names?

I need to do some assigns as follows.
In struct REGS, tiles are arranged by names;
while on outside, tiles are arranged by indices.
#include <stdio.h>
typedef struct TILE {} TILE;
typedef struct REGS {
TILE tile00, tile01, tile02,
tile10, tile11, tile12,
tile20, tile21, tile22;
} REGS;
int main() {
TILE tiles[3][3];
REGS regs;
regs.tile00 = tiles[0][0];
regs.tile01 = tiles[0][1];
regs.tile02 = tiles[0][2];
regs.tile10 = tiles[1][0];
regs.tile11 = tiles[1][1];
regs.tile12 = tiles[1][2];
regs.tile20 = tiles[2][0];
regs.tile21 = tiles[2][1];
regs.tile22 = tiles[2][2];
return 0;
}
so I suppose I need a loop like:
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
// not real code
regs.tile##i##j = tiles[i][j];
}
}
for doing that, I defined some macros:
#define TILE_MEM(prefix, i, j) prefix##i##j
#define WRITE_TILE(base, mem, value) (base.mem = value;)
#define MACRO_LOOP(i,j) (WRITE_TILE(regs, TILE_MEM(tile, i, j), tiles[i][j]))
then I did this:
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
MACRO_LOOP(i, j);
}
}
but it doesn't compile.
PLEASE HELP!
Macros are the wrong solution and they only exist at compile-time, so you can't use them together with run-time values.
The standard way of creating a type where you can either access items by individual names or as an array, is to use a union:
typedef union {
struct // anonymous struct, must be compiled with a standard C compiler
{
TILE tile00, tile01, tile02,
tile10, tile11, tile12,
tile20, tile21, tile22;
};
TILE tile [3][3];
} REGS;
Now you can either use individual names:
regs.tile00 = tiles[0][0];
regs.tile01 = tiles[0][1];
Or the array type:
for(size_t i=0; i<3; i++)
{
for(size_t j=0; j<3; j++)
{
regs.tile[i][j] = tiles[i][j];
}
}
(Do keep struct alignment/padding in mind however, since there's some special cases where that might trip union type punning over.)

Is there a way to warn about this pointer bug?

The situation is that I have an array of struct
tree_t tree[MAXTREES];
and I have been using a pointer to access the array's elements
for(int i = 0; i < MAXTREES; i++) {
tree_t *tptr = tree + i;
// ...
}
To make the code easier to manage - compare these simple examples:
int num;
num = tree[i].node[j].left; // could be like this
num = tptr->node[j].left; // but I am using this
That's the situation, but I made a bug by mistakenly typing
num = tree->node[j].left;
and because the array decays to a pointer to its first element, it's valid C code and it took me a while to spot what I had done wrong.
Is there a way to get a warning about this? Or is it just poor programming style?
Here is a compilable example, it's not worth actually runnning.
#include <stdint.h>
#define MAXLEAFS 16384
#define MAXTREES 15262
typedef struct {
int16_t left;
int16_t right;
} leaf_t;
typedef struct tree_t {
leaf_t node[MAXLEAFS];
int spudbase;
int root;
int width;
int spudics;
struct tree_t *nextree;
} tree_t;
tree_t tree[MAXTREES];
int main(void)
{
for(int i = 0; i < MAXTREES; i++) {
tree_t *tptr = tree + i;
for (int j = 0; j < MAXLEAFS; j++) {
int num;
num = tree[i].node[j].left; // could be like this
num = tptr->node[j].left; // but I am using this
num = tree->node[j].left; // this is my bug
}
}
}
Edit: To illustrate why I am doing this, here is a snippet of my actual code, which I simplified to ask the question. I am using a pointer to the struct to avoid nesting the array indexing here:
tree[index].spudics = tree[index].node[tree[index].root].left +
tree[index].node[tree[index].root].right;
and simplify with
tptr->spudics = tptr->node[tptr->root].left + tptr->node[tptr->root].right;
which IMO is more readable.
This is an avoidable problem. If you rewrite this to use iterator pointers you get code like this:
int main(void)
{
tree_t *tptr = tree;
for (int i = 0; i < MAXTREES; ++i, ++tptr) {
leaf_t *leaf = tptr->node;
for (int j = 0; j < MAXLEAFS; ++j, ++leaf) {
int num = leaf->left;
}
}
}
This avoids a lot of problems because you're using very focused pointers and there's really no reason to do things like leaf[j].left by accident. The correct code looks simple. The incorrect code looks broken.

C - Declaring a global array within a function not possible. Other solutions?

Here's what I'm trying to do:
I need a global array with a length that is dependent on a variable (NumOfRequests). That variable is set within a function. I don't think it's possible to declare a global array within a function as I tried to do in the following code:
static uint8 NumOfRequests;
typedef struct
{
uint16 IndexToRequest;
GdXRequestData_ts RequestData;
bool RequestSent;
} GdRequests;
static void SetupRequestStructures( void )
{
uint8 i;
for( i = 0; EepromData_ps.GD_Indices[i] != 0xFFFF; i++ )
{
NumOfRequests = i + 1;
}
GdRequests Requests[NumOfRequests];
for( i = 0; i < NumOfRequests; i++ )
{
Requests[i].IndexToRequest = EepromData_ps.GD_Indices[i];
}
}
It's not possible to declare an array and later decide what length it should be or change its length, as far as I know.
So does anyone know another solution for how to declare a global array with a length based on a variable that is set within a function?
Any feedback is appreciated. If you upvote or downvote, tell me why so I can improve with future questions.
You can use dynamic memory allocation to perform this task. Look at malloc and free. Here's a simple example of dynamic memory allocation on a global array of structs:
#include <stdio.h>
#include <stdlib.h>
typedef struct _MyStruct
{
int a;
int b;
} MyStruct;
MyStruct *g_Array = NULL;
void populatearray(MyStruct *array, int length)
{
int i;
for(i = 0; i < length; i++)
{
array[i].a = i;
array[i].b = i;
}
}
void printstructs(MyStruct *array, int length)
{
int i;
for(i = 0; i < length; i++)
{
printf("array[%d].a = %d\narray[%d].b = %d\n\n", i, array[i].a, i, array[i].b);
}
}
int main()
{
g_Array = malloc(50 * sizeof(MyStruct));
if(!g_Array)
{
puts("Malloc failed");
return 0;
}
populatearray(g_Array, 50);
printstructs(g_Array, 50);
free(g_Array);
return 0;
}

how to make an array with my struct types?

In C#.NET I can to use List<myclasstype> vals = new List<myclasstype> (); it's possible do equivalent to in C?
I have an struct like:
typedef struct foo {
int x;
int y;
} Baa;
and I want do:
**BAA vals = ??
int i ;
for(i = 0; i < size; i++)
{
vals[i].x = i;
vals[i].y = i * 10;
}
I hope this is clear for you. Thanks in advance.
It is the same as you would create any other array in C except that the type is replaced with Baa
int size = 5;
Baa baaArray[size];
int i;
for(i = 0; i < size; i++)
{
baaArray[i].x = i;
baaArray[i].y = i*10;
}
You can also use pointers and malloc to accomplish this:
int size = 5;
Baa *baaPtr = malloc(sizeof(Baa) * size);
//...
Hope this helps.

C and dynamic structure element access

I have this complicated structure thingie:
#include <stdlib.h>
typedef struct {
int x;
int y;
} SUB;
typedef struct {
int a;
SUB *z;
} STRUCT;
#define NUM 5
int main(void)
{
STRUCT *example;
int i;
example = malloc(sizeof(STRUCT));
example->z = malloc(NUM * sizeof(SUB));
for(i = 0; i < NUM; ++i) {
/* how do I access variable in certain struct of array of z's */
}
return 0;
}
example is dynamically allocated structure and z inside the example is dynamically allocated array of SUB structures.
How do I access certain variable in certain element of structure z?
I have been trying something like this: example->z[i].x but it doesnt seem to work.
At the moment I am using this shabby looking workaraound:
SUB *ptr = example->z;
int i;
for(i = 0; i < amount_of_z_structs; ++i) {
/* do something with 'ptr->x' and 'ptr->y' */
ptr += sizeof(SUB);
}
Your problem isn't where you say it is. Your code as posted gives a compile error:
error: request for member ā€˜zā€™ in something not a structure or union
at the line
example.z = malloc(sizeof(STRUCT));
because you meant to write example->z, since example is a pointer to STRUCT, not a STRUCT.
From there on, you can access example->z[i].x exactly as you said. That syntax has always been fine.
For example:
/* your declarations here */
example = malloc(sizeof(STRUCT));
example->z = malloc(NUM * sizeof(SUB));
for(i = 0; i < NUM; ++i) {
example->z[i].x = i;
example->z[i].y = -i;
printf("%d %d\n", example->z[i].x, example->z[i].y);
}
/* output:
0 0
1 -1
2 -2
3 -3
4 -4
*/
When you have pointers pointing to pointers you often end up running into precedence issues. I can't recall if this is one, but you might try (example->b)[i].x.
First of all, your second malloc is wrong; example is a pointer so this:
example.z = malloc(NUM * sizeof(SUB));
should be this:
example->z = malloc(NUM * sizeof(SUB));
Then in your loop you can say things like this:
example->z[i].x = i;
example->z[i].y = i;
You'll also want to have this near the top of your file:
#include <stdlib.h>
Try this:
int my_x = example[3].z[2].x;
The above code will first access the example[3] (the fourth element of the example array).
Once you get that particular element, its contents can be automatically access in the same way as you do with normal objects.
You then access z[2] from that element. Note that, example[3] is an element, so you could use a . to access its members; if its an array, you can access it as an array.
So till now, example[3].z[2] is one element of the SUB array inside one element of the example array.
Now you can simply access the member x using the way shown above.
typedef struct {
int x;
int y;
} SUB;
typedef struct {
int a;
SUB *z;
} STRUCT;
STRUCT *example;
int main() {
example = malloc(sizeof(STRUCT)*10); //array of 10;
int i=0,j=0;
for (;i<10;i++){
example[i].a = i;
example[i].z = malloc(sizeof(SUB)*5);
for (j=0; j<5; j++)
example[i].z[j].x = example[i].z[j].y = j;
}
//access example[3] and access z[2] inside it. And finally access 'x'
int my_x = example[3].z[2].x;
printf("%d",my_x);
for (i=0;i<10;i++){
printf("%d |\n",example[i].a);
//example[i].z = malloc(sizeof(SUB)*5);
for (j=0; j<5; j++)
printf("%d %d\n",example[i].z[j].x,example[i].z[j].y);
free(example[i].z);
}
free(example);
}
In the 'shabby workaround', you wrote:
SUB *ptr = example->z;
int i;
for(i = 0; i < amount_of_z_structs; ++i) {
/* do something with 'ptr->x' and 'ptr->y' */
ptr += sizeof(SUB);
}
The problem here is that C scales pointers by the size of the object pointed to, so when you add 1 to a SUB pointer, the value is advanced by sizeof(SUB). So, you simply need:
SUB *ptr = example->z;
int i;
for (i = 0; i < NUM; ++i) {
ptr->x = ptr->y = 0;
ptr++;
}
Of course, as others have said, you can also do (assuming C99):
for (int i = 0; i < NUM; ++i)
example->z[i].x = example->z[i].y = 0;
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#define NUM 5
typedef struct
{
int x;
int y;
}SUB;
typedef struct
{
int a;
SUB* z;
}STRUCT;
void main(void)
{
clrscr();
printf("Sample problem..\n\n");
STRUCT* example;
int i;
example = (STRUCT*)malloc(sizeof(STRUCT));
example->z = (SUB*)malloc(NUM * sizeof(SUB));
for(i = 0; i < NUM; i++)
{
example->z[i].x = i +1;
example->z[i].y = (example->z[i].x)+1;
printf("i = %d: x:%d y:%d\n", i, example->z[i].x, example->z[i].y);
}
}

Resources