How to loop over variable names? - c

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.)

Related

Incompatible types when assigning to type ‘int[100][1000]’ from type ‘int (*)[1000]

I have to make 2 programs. One that write a matrix on a shared memory and one that must read and order this matrix.
I created a shared structure that is the var that I will put on the shared memory. But I don't know how to read and store on another var.
My shared structure:
#define QUANTIDADE 100
#define TAMANHO 1000
struct shared_use_st {
int written_by_you;
int num_processos_executando;
int arrays[QUANTIDADE][TAMANHO];
};
How I create my matrix on the writer code:
int i, j;
for (j = 0; j < QUANTIDADE; j++) {
for (i = 0; i < TAMANHO; i++) {
shared_stuff->arrays[j][i] = rand();
}
}
How I want to read from the memory:
int my_arrays[QUANTIDADE][TAMANHO];
int main() {
[...]
my_arrays = shared_stuff->arrays; //Error
[...]
}
You can't assign to an array directly. You'll need to copy each element:
int i, j;
for (j = 0; j < QUANTIDADE; j++){
for (i = 0; i < TAMANHO; i++) {
my_arrays[j][i] = shared_stuff->arrays[j][i];
}
}
Or use memcpy:
memcpy(my_arrays, shared_stuff->arrays, sizeof(my_arrays));

Passing 2D array to a Function: zero-value and print issue

I want to pass 2D array to a function. I've written 3 functions:
make all the values == 0;
implement it with desired values;
print matrix;
My output looks wrong. I checked in debug mod that mapZero works right (it implements zeros by all rows and columns but). The first matrix must consist of only zero values, the second one with implemented (btw, why my commented code in mapInit can't be built? It seems I did it right). and the third matrix is a new matrix implemented with my algorithm (I'm writin wave-algorithm to find the shortest way to a final point).
I can't get how and where I should use pointers (maybe the problem is in it?) and how to pass WIDTH and HEIGHT with a right way.
int mapZero(int * map[WIDTH][WIDTH])
{
for (int i = 0; i < WIDTH; ++i)
{
for (int j = 0; j < HEIGHT; ++j)
{
map[i][j] = 0;
}
}
}
int mapPrint(int map[WIDTH][HEIGHT])
{
for (int i = 0; i < WIDTH; ++i)
{
for (int j = 0; j < HEIGHT; ++j)
{
printf("%2d ", map[i][j]);
}
printf("\n\n");
}
printf("\n");
return 0;
}
int mapInit(int * map[WIDTH][WIDTH])
{
/*
map[WIDTH][WIDTH] =
{
{ 127,1,1,1,1,1,1, 1 },
{ 0, 1,0,0,0,1,1, 1 },
{ 1, 1,1,1,0,0,0, 1 },
{ 1, 0,0,1,0,0,0, 1 },
{ 1, 0,1,1,0,0,1, 1 },
{ 1, 1,1,1,1,1,1, 1 },
{ 0, 1,0,0,1,0,1, 1 },
{ 1, 1,1,1,1,1,1,255 },
};
*/
for (int i = 0; i < WIDTH; ++i)
{
for (int j = 0; j < HEIGHT; ++j)
{
map[i][j] = 0;
}
}
for (int j = 0; j < WIDTH; ++j)
{
map[0][j] = 1;
map[7][j] = 1;
map[j][7] = 1;
map[5][j] = 1;
}
for (int j = 2; j < 5; ++j)
{
map[j][0] = 1;
}
map[1][1] = 1; map[1][5] = 1; map[1][6] = 1;
map[2][1] = 1; map[2][2] = 1; map[2][3] = 1;
map[3][3] = 1;
map[4][2] = 1; map[4][3] = 1; map[4][6] = 1;
map[6][1] = 1; map[6][4] = 1; map[6][6] = 1; map[6][7] = 1;
map[0][0] = 22;
map[7][7] = 99;
return 0;
}
My main.c:
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#define WIDTH 8
#define HEIGHT 8
int mapZero(int * map[WIDTH][WIDTH]);
int mapPrint(int map[WIDTH][HEIGHT]);
int mapInit(int * map[WIDTH][WIDTH]);
int main(int argc, char * argv[])
{
short int map[WIDTH][HEIGHT];
short int visited[WIDTH][HEIGHT];
mapZero(visited);
mapZero(map);
mapInit(map, WIDTH, HEIGHT);
printf("Matrix of zeroed-visited cells:\n\n");
mapPrint(visited, WIDTH, HEIGHT);
printf("Matrix of the map:\n\n");
mapPrint(map, WIDTH, HEIGHT);
return 0;
}
The argument declaration int * map[WIDTH][WIDTH] is equal to int * (*map)[WIDTH]. That's an array of array of pointers to int. You pass an array of array of short int.
Drop the asterisk, use the correct type in the arguments, and the correct symbolic constant: short int map[WIDTH][HEIGHT].
You also call mapInit and mapPrint with two extra arguments that are not in the declared functions.
The compiler should have complained about all of this.
int * map[WIDTH][WIDTH] is an array of pointers. It is not compatible with the array in the caller so the code should not compile. Change this to int map[WIDTH][WIDTH].
Similarly, an array of short is not necessarily compatible with an array of int. Use the same type everywhere.
If your code compiled without errors/warnings there's something very wrong with your compiler.
By the rule of array parameter adjustment ("decay"), the above array declaration, when part of a parameter list, will get adjusted by the compiler to the pointer to the first element. The first element of the 2D array is a 1D array, so it gets adjusted to an array pointer to a 1D array, int (*)[WIDTH].

Access fields of a struct dynamically

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.

Pass static two dimensional struct array to function by reference

I try to pass a static two dimensional struct as a reference to a function.
But I don't know how to get that done in correct way.
From my understanding, I pass a pointer to the first element of struct test to initfield(). C does know the size of the struct test so I can jump to the specific requested locations of the data. I just don't know how to adress the required data.
Here's my code that hopefully describes what I am looking for.
struct test{
int i;
double d;
};
void initfield(struct test *a, int structsize)
{
int i, j;
for (i = 0; i < structsize; i++)
{
for (j = 0; j < structsize; j++)
{
a[i][j]->i = 1;
a[i][j]->d = 1.0;
}
}
}
int main(void)
{
int i, j;
struct test field[8][8];
initfield(field, 8);
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
printf("test[%i][%i].i = %i", i, j, test.i);
printf("test[%i][%i].d = %i", i, j, test.d);
}
}
return 0;
}
Update :
I've replaced both printf's with the following :
printf("test[%i][%i].i = %i", i, j, field[i][j].i);
printf("test[%i][%i].d = %lf", i, j, field[i][j].d);
However, I still encounter errors with initfield.
The problem, is actually, in your initfield() code,
void initfield(struct test *a, int structsize)
a is of type struct test *, and later, you're doing
a[i][j]->i = 1;
which expects a to be struct test **
That said,
for (j = 0; j < 8; j++)
{
printf("test[%i][%i].i = %i", i, j, test.i);
printf("test[%i][%i].d = %i", i, j, test.d);
}
is completely wrong. Neither is there any variable called test, nor you can access a 2-D array using structVar.membervar format. Moreover, you are using %d to print a double, which in turn invokes undefined behaviour.
Solution: You can make use of array properties and pointer arithmetic to achieve what you want.
You have to change the loop inside the initfield() code, like
for (i = 0; i < structsize; i++)
{
for (j = 0; j < structsize; j++)
{
((a+(i*structsize))+j)->i = 7; //I changed the value to store, just like that
((a+(i*structsize))+j)->d = 2.0; //I changed the value to store, just like that
}
}
and, in main(), use %f to print the values.
A Live variant
First, structsize is not a good identifier name. It's not the size of the struct, it's the size of one dimension of the array. I'd implement it with parameters x and y, or width and heigth, or any better names for the two dimensions.
field is also a bad name. A field is often used to call a member of a struct. It is very confusing to use the identifier field to call an array of array of structs.
Then to your problem: field is an array of array of structs. In function parameter, this is equivalent to a pointer to a pointer.
The first parameter of initfield should be of type struct test **. Then later in the function, you dereference twice with your [] operators:
a is of type struct test **
a[i] is of type struct test *
a[i][j] is of type struct test
To access the fields of a[i][j], you need the . operator since its a struct test: a[i][j].d. The operator -> would work if a[i][j] was of type struct test *, but it isn't.
In this case it doesn't matter: as other have said, you can't access the second dimension of the array without explicitly calculating with the help of the size of the first dimension. a[i][j] does not work, you need some kind of pointer arithmetic: struct test *p = a + i * structsize + j and use p->i and p->d.
In the main function however, the dimensions of field are know, so field[i][j].d works.
You're assuming C can figure out that a inside refers to a square array with side length structsize, although you clearly say that a has type "pointer to struct test", which is not the same.
You need to do the indexing manually, inside the function:
static void initfield(struct test *a00, size_t sidelength)
{
for(size_t i = 0; i < sidelength; ++i)
{
for(size_t j = 0; j < sidelength; ++j)
{
struct test *aij = a00 + i * sidelength + j;
aij->i = 1;
aij->j = 1.0;
}
}
}
I didn't test the above, but something like that should work. It basically just uses simple pointer arithmetic to compute the address of the 2D array element at (i, j) given the address of the one at (0, 0).
It works fine i din't thought about doing calculation the adresses myself.
Thanks very much!
Here's my final adapted code which just works perfectly!
struct test{
int i;
double d;
};
void initfield(struct test *a00, int structsize)
{
int i, j;
for (i = 0; i < structsize; i++)
{
for (j = 0; j < structsize; j++)
{
struct test *acurrent = a00 + i * structsize + j;
acurrent->i = 1;
acurrent->d = 1.0;
}
}
}
int main(void)
{
int i, j;
struct test field[8][8];
initfield(&field[0][0], 8);
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
printf("test[%i][%i].i = %i\n", i, j, field[i][j].i);
printf("test[%i][%i].d = %lf\n", i, j, field[i][j].d);
}
}
return 0;
}
Best way to do this:
void initfield(size_t x, size_t y, struct test a[x][y]);
Be aware though, C is strange, the above is still a pointer, equivalent to struct test*. If you wish to have a true array pointer type, you'd have to do:
void initfield(size_t x, size_t y, struct test a[x][y])
{
struct test (*ptr)[x][y] = (void*)a;
or preferably:
struct test (*ptr)[y] = *a;
ptr[i][j] = something; // use the array pointer with sane syntax

C reshape 1d to 2d

I want to reshape an array of length L to one of MxN, however rather than create new memory by copying the elements over in for loops I'd like to do some pointer casting to allow me to access the array with double subscripting (array[X][Y]) .
I've googled around for ages and couldn't find anything helpful.
Any help would really be appreciated.
EDIT: The array of interest is on the heap not stack.
Pointer casting doesn't seem like a good idea here. But if the number of columns is known before run-time, one option I often encounter is to simply define a macro e.g.
#define arrayName(i,j) arrayName[((i)*N) + (j)]
Or
#define ELEMENT(arrayName, i,j) (arrayName)[((i)*N) + (j)]
if you want it to be more flexible.
unions are your friends:
#include <stdio.h>
#define M 5
#define N 4
typedef union {
int a1[M * N];
int a2[M][N];
} U;
int main()
{
U u;
int i, j;
for (i = 0; i < M * N; ++i)
{
u.a1[i] = i;
}
for (i = 0; i < M; ++i)
{
for (j = 0; j < N; ++j)
{
printf("%8d", u.a2[i][j]);
}
printf("\n");
}
return 0;
}
typedefs are your friends:
#include <stdio.h>
#include <stdlib.h>
#define M 5
#define N 4
typedef int Array1D[M * N];
typedef int Array2D[M][N];
int main()
{
Array1D *a1 = malloc(sizeof(*a1));
Array2D *a2 = (Array2D *)a1;
int i, j;
for (i = 0; i < M * N; ++i)
{
(*a1)[i] = i;
}
for (i = 0; i < M; ++i)
{
for (j = 0; j < N; ++j)
{
printf("%8d", (*a2)[i][j]);
}
printf("\n");
}
free(a1);
return 0;
}
Note: above code has now been updated to use heap allocation so as not to break strict aliasing rules.
By the way if you want it super dynamic (as in no sizes are known at compile-time) you can do this by not copying all the values but by creating an index for the 2nd dimension like so:
#include <stdio.h>
#include <stdlib.h>
const int FULL = 100;
const int X = 10;
const int Y = 10;
int *dim1;
int **nested;
int main(void) {
dim1 = malloc(sizeof(int)*FULL);
nested = malloc(sizeof(int*)*X);
for(int i=0; i<X;i++)
{
nested[i] = &dim1[Y*i];
}
dim1[15] = 42;
printf("nested[1][5]: %d",nested[1][5]);
free(nested);
free(dim1);
return 0;
}

Resources