C pointer array with elements of other pointer array - arrays

I have 2x structs, one for color (PixelColor) and the second for holding an array of available colors (Palette).
typedef struct{
int r;
int g;
int b;
int a;
}PixelColor;
typedef struct{
int size;
PixelColor *palette;
}Palette;
One game's global palette and one for objects that reference colors in the global palette.
PixelColor ShovelKnightColors[] = {
{0, 0, 0, 255},
{44, 44, 44, 255},
{96, 96, 96, 255},
{200, 192, 192, 255},
{0, 64, 88, 255},
...
};
Palette GamePalette = {59, ShovelKnightColors};
PixelColor CharacterColors[4];
//This doesn't work
CharacterColors[0] = GamePalette.palette[0];
CharacterColors[1] = GamePalette.palette[17];
CharacterColors[2] = GamePalette.palette[24];
CharacterColors[3] = GamePalette.palette[37];
Palette CharacterPalette = {4, CharactersColors};
I'm probably missing a fundamental thing, but I tried any idea I had. As an example:
PixelColor CharacterColors[] = {
GamePalette.palette[0],
GamePalette.palette[17],
GamePalette.palette[24],
GamePalette.palette[37]
}
All this is outside the main function, just to learn things I don't know about initiation. Please suggest a way to get closest to the initial idea of referencing the same values, because the goal is to create an ESP32 microcontroller project.

The problem with your code has to do with the fact that you have arrays inside your structs, and arrays need to be initialized.
My suggestion would be to create a FillPalette() function that would do the appropriate memory allocation each time:
void FillPalette(Palette *p, int size, PixelColor pixelColors[])
{
p->size = size;
p->palette = malloc( sizeof(PixelColor) * size );
for(int i = 0; i < size; ++i)
{
p->palette[ i ].r = pixelColors[ i ].r;
p->palette[ i ].g = pixelColors[ i ].g;
p->palette[ i ].b = pixelColors[ i ].b;
p->palette[ i ].a = pixelColors[ i ].a;
}
}
Another possibility, in order to avoid the for loop, is to use memcopy once the array has been initialized.
Anyway, remember to clear the palette when is not going to be used anymore:
void ClearPalette(Palette *p)
{
p->size = 0;
free( p->palette );
}

Related

Initialize a flexible array of arrays in a struct

The title corresponds to my last attempt, I try to store color values ​​corresponding to walls, a bit like this:
#include <stdint.h>
typedef uint8_t RGB[3];
typedef RGB ColorArray[];
typedef struct {
int wall_num;
ColorArray wall_colors;
} Map;
int main(void)
{
int wall_num = 3;
ColorArray wall_colors = {
*(RGB){ 255, 0, 0 },
*(RGB){ 0, 255, 0 },
*(RGB){ 0, 0, 255 }
};
Map my_map = {wall_num, wall_colors}; // error: non-static initialization of a flexible array member
return 0;
}
But I get this:
error: non-static initialization of a flexible array member
I tried other ways with pointers but I quickly realized that it was pointing to anything and so I got any colors until a segfault...
Is there a way to do it like this ? Or is it just the wrong way to go and I have to start all over again ?
UPDATE - (SELF ANSWER):
So I decided to call malloc() because no alternative was satisfactory for my case, I share what I did if it can help someone:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef uint8_t RGB[3];
typedef RGB RGB_Array[];
typedef struct {
int wall_num;
RGB_Array wall_colors;
} Map;
void print_map (Map *m) {
printf("wall_num: %d\n", m->wall_num);
for (int i = 0; i < m->wall_num; ++i) {
printf("wall_colors[%d]: (R:%d, G:%d, B:%d)\n", i,
m->wall_colors[i][0],
m->wall_colors[i][1],
m->wall_colors[i][2]);
}
}
int main(void)
{
int wall_num = 3;
RGB_Array color_arr = {
{255,0,0},
{0,255,0},
{0,0,255}
};
Map* map = malloc(sizeof(Map) + sizeof(color_arr));
map->wall_num = wall_num;
memcpy(map->wall_colors, color_arr, sizeof(color_arr));
print_map(map);
free(map); // free is for example
return 0;
}
Otherwise, jxh's answer is still interesting and perfectly does what was asked for, even if it doesn't suit me personally, I validate it anyway.
You cannot use an array name to initialize an array variable anyway.
There is no memory associated with the flexible array member. It is a convenience to allow you to have a name for the end of the struct to refer to the array that you intend to allocate behind the struct.
Typically, you would use malloc() and add the size of the array to the size of the struct to get a single object to represent your structure with the flexible array.
However, you can do it off the "stack" by defining a new structure where the flexible array member is replaced with an array of the appropriate size, and then casting a pointer to this structure to your desired type.
Alternatively, you could use a union and avoid the casting.
Both techniques are illustrated below. First some helpers:
...
#define MAP_TEMPLATE(N) struct { \
int wall_num; \
RGB wall_colors[N]; \
}
...
void print_map (Map *m) {
printf("wall_num: %d\n", m->wall_num);
for (int i = 0; i < m->wall_num; ++i) {
printf("wall_colors[%d]: (R:%d, G:%d, B:%d)\n", i,
m->wall_colors[i][0],
m->wall_colors[i][1],
m->wall_colors[i][2]);
}
}
Then using a new structure:
MAP_TEMPLATE(3) my_map1 = {
wall_num,
{ { 155, 0, 0 },
{ 0, 155, 0 },
{ 0, 0, 155 },
},
};
print_map((Map *)&my_map1);
And using a union:
union {
MAP_TEMPLATE(3) _;
MAP_TEMPLATE();
} my_map2 = {
{ wall_num,
{ { 255, 0, 0 },
{ 0, 255, 0 },
{ 0, 0, 255 },
},
},
};
print_map((Map *)&my_map2);

Suggested way to initialize a struct in C

Is there a suggested way on how to initialize a struct in C? For example:
Book romeo = {"Romeo & Juliet", "Shakespeare", 1600};
Book inferno;
inferno.title = "Divine Comedy";
inferno.author = "Dante";
inferno.year = 1400;
Is one way preferred over the other one? I would think for readability the second one is easier, but if there are a ton of fields it might become unwieldy. Additionally, is there any way to specify the variable name in the first method, something like:
Book romeo = {title="...", author="...", year="...");
Additionally, is there any way to specify the variable name in the
first method, something like:
hope below code helps
#include<stdio.h>
typedef struct Book {
char *title;
unsigned int year;
} Book;
int main()
{
Book B1 = { .year = 1999};
Book B2 = {.title= "Jason Bourne", .year = 1999};
printf("B1.year = %d\n", B1.year);
printf("B2.title = %s B2.year = %d\n", B2.title, B2.year);
return 0;
}
Is one way preferred over the other one?
Note: C defines the first as initialization, the 2nd as assignment.
Yes, global object can be initialized, but not assigned with global code.
// Possible
Book romeo = {"Romeo & Juliet", "Shakespeare", 1600};
Book inferno;
// Not possible outside a function.
inferno.title = "Divine Comedy";
inferno.author = "Dante";
inferno.year = 1400;
is there any way to specify the variable name in the first method
Since C99, members can be specified in any order, complete or not.
Book romeo = {. title = "Romeo & Juliet", .author = "Shakespeare", .year = 1600};
Book romeo = {.year = 1600, . title = "Romeo & Juliet", .author = "Shakespeare" };
Book romeo = {. title = "Romeo & Juliet", .author = "Shakespeare" }; // .year takes on value 0
Yes, there's a way but not exactly as you said.
#include <stdio.h>
typedef struct { int k; int l; int a[2]; } T;
typedef struct { int i; T t; } S;
T x = {.l = 43, .k = 42, .a[1] = 19, .a[0] = 18 }; // x initialized to {42, 43, {18, 19} }
int main(void)
{
S l = { 1, // initializes l.i to 1
.t = x, // initializes l.t to {42, 43, {18, 19} }
.t.l = 41, // changes l.t to {42, 41, {18, 19} }
.t.a[1] = 17 // changes l.t to {42, 41, {18, 17} }
};
printf("l.t.k is %d\n", l.t.k); // .t = x sets l.t.k to 42 explicitly
// .t.l = 41 would zero out l.t.k implicitly
}
Moreover, you should visit this once
and please check here before you ask a question.

Cannot draw polygons using XCB in C

Just started with XCB programming with C. I have written this code which will create a window and draw some points and a rectangle:
#include <stdlib.h>
#include <stdio.h>
#include <xcb/xcb.h>
int main() {
xcb_connection_t *connection = xcb_connect(NULL, NULL);
if (xcb_connection_has_error(connection)) {
printf("Error setting up connection to X\n");
exit(1);
}
const xcb_setup_t *setup = xcb_get_setup(connection);
xcb_screen_t *screen = xcb_setup_roots_iterator(setup).data;
// Create wndow
xcb_window_t window_id = xcb_generate_id(connection);
uint32_t prop_name = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
uint32_t prop_value[2];
prop_value[0] = screen->white_pixel;
prop_value[1] = XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_EXPOSURE;
xcb_create_window(connection, screen->root_depth, window_id, screen->root, 100, 100, 500, 400, 1,
XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, prop_name, &prop_value);
xcb_map_window(connection, window_id);
xcb_flush(connection);
uint32_t gc_value_mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
uint32_t gc_value_list[2];
gc_value_list[0] = screen->black_pixel;
gc_value_list[1] = 0;
xcb_drawable_t drawable_window = screen->root;
xcb_gcontext_t context_id = xcb_generate_id(connection);
xcb_void_cookie_t cookie = xcb_create_gc(connection, context_id, drawable_window, gc_value_mask, gc_value_list);
// Create polygons
xcb_point_t points[5] = {{10, 10}, {10, 50}, {40, 70}, {70, 40}, {50, 10}};
xcb_rectangle_t rect = {50, 50, 100, 50};
// Main loop
xcb_generic_event_t *event;
while ((event = xcb_wait_for_event(connection))) {
switch (event->response_type) {
case XCB_KEY_PRESS:
break;
case XCB_BUTTON_PRESS:
break;
case XCB_EXPOSE:
printf("Expose event called\n");
// Draw polygons
xcb_poly_point(connection, XCB_COORD_MODE_ORIGIN, drawable_window, context_id, 4, points);
xcb_poly_fill_rectangle(connection, drawable_window, context_id, 1, &rect);
xcb_flush(connection);
default:
break;
}
free(event);
}
return 0;
}
It has compiled properly and there was no warning or error at runtime. But, I just get a window with no graphics. What am I doing wrong?
I think your xcb_poly_fill_rectangle(), etc., are trying to draw on the root window. At least, you're passing screen->root as the drawable argument. It works for me if I pass window_id here.
I'm really not sure why XCB needs all these various context arguments, and the exact functions of each do not seem to be well-documented.
Kevin Boone is correct: You are drawing to the root window.
I did the following change to your program (it is the same one that Kevin suggested):
--- t.c.orig 2020-09-18 15:06:38.344441255 +0200
+++ t.c 2020-09-18 15:06:48.104167556 +0200
## -26,7 +26,7 ## int main() {
uint32_t gc_value_list[2];
gc_value_list[0] = screen->black_pixel;
gc_value_list[1] = 0;
- xcb_drawable_t drawable_window = screen->root;
+ xcb_drawable_t drawable_window = window_id;
xcb_gcontext_t context_id = xcb_generate_id(connection);
xcb_void_cookie_t cookie = xcb_create_gc(connection, context_id, drawable_window, gc_value_mask, gc_value_list);
This results in the following window contents being shown. You can see both the rectangle and the individual pixels being shown:
Please do not accept this answer, but instead Kevin Boone's. I only wanted to add the screenshot.

Sending pointer to a struct through a queue in FreeRTOS

I can't seem to figure out how to send a pointer to a struct using a queue in FreeRTOS. I've tried all I could think of, yet I always get a pointer to some random region of memory.
I'm trying to send a pointer to a button struct to another task, where it will then be drawn on the screen. I tried sending the whole object and it worked, but since there's a lot of data in the struct (data of two icons) I don't really want to do that.
The code is being run in Atmel SAME70 Xplained.
Here is a simpler version of the code I'm working on:
typedef struct {
uint32_t width;
uint32_t height;
uint32_t x;
uint32_t y;
uint8_t status;
void (*callback)(t_but);
tImage iconOn;
tImage iconOff;
} t_but;
void task_lcd(void) {
xQueueButtons = xQueueCreate(6, sizeof(struct t_but *));
t_but *button;
configure_lcd();
draw_screen();
while (1) {
if (xQueueReceive(xQueueButtons, &(button), (TickType_t)500 / portTICK_PERIOD_MS)) {
// This always prints some random numbers.
printf("Button X: %" PRIu32 "\r\n", button->x);
}
}
}
void task_buttons(void) {
t_but butPlay = {.width = 64,
.height = 64,
.x = 60,
.y = 445,
.status = 0,
.callback = &ButPlayCallback,
.iconOn = play_red,
.iconOff = play_black};
xQueueSend(xQueueButtons, &butPlay, 0);
while (1) {
// Some other code.
}
}
Any help is very much appreciated.
It appears from the API that the xQueueSend does a copy via the pointer passed so if you want to pass a pointer on the queue you need to pass the address of a pointer that is pointing at your structure.
void task_buttons(void) {
t_but butPlay = {.width = 64,
.height = 64,
.x = 60,
.y = 445,
.status = 0,
.callback = &ButPlayCallback,
.iconOn = play_red,
.iconOff = play_black};
t_but * const p_but = &butPlay;
xQueueSend(xQueueButtons, &p_but, 0);
while (1) {
// Some other code.
}
}

Sorting an struct array in C with qsort function

First of all, I saw some examples like:
sorting members of structure array
C Array sorting tips
But they don't work for me.
My struct is
typedef struct Team {
int total;
char name[N][N]; // Nombre
int points[N]; // Points
int pg[N]; // Won Matches
int pe[N]; // Tied Matches
int pp[N]; // Lost Matches
int gf[N]; // Goals For
int gc[N]; // Goals Against
} Teams;
int compareTeams(struct Team *e1, struct Team *e2){
int comparer;
int dg1 = e1->gf - e1->gc;
int dg2 = e2->gf - e2->gc;
//classified according to the points
if (e1->points > e2->points) {
comparer=-1;
} else if (e1->points < e2->points) {
comparer=1;
} else {
// with the same points, goal difference check
if (dg1 > dg2) {
comparer=-1;
} else if (dg1 < dg2) {
comparer=1;
} else {
// with the same goal difference , we check who scored more goals
if(e1->gf > e2->gf) {
comparer=-1;
} else if (e1->gf < e2->gf) {
comparer=1;
} else
comparer=0;
}
}
return comparer;
}
In main function, I have this:
Teams teams[100];
qsort(teams, teams->total, sizeof(struct Team), &compareTeams);
But obviously, it doesn't work :(
You have a single struct:
typedef struct Team {
int total;
char name[N][N]; // Nombre
int points[N]; // Points
int pg[N]; // Won Matches
int pe[N]; // Tied Matches
int pp[N]; // Lost Matches
int gf[N]; // Goals For
int gc[N]; // Goals Against
} Teams;
This struct is misnamed; it is not a team, it is a league. All fields except total are themselves arrays. If you want to sort this struct, you would have to swap all arrays simultaneously, because they are essentially independent. qsort can't do that; you would have to write your own sorting algorithm.
It makes managing the teams and also sorting easier when you restructure your data: A team should only contain the data for itself:
typedef struct Team {
char name[24];
int points; // Points
int won, drawn, lost; // Match records
int scored, conceded; // Goal records
} Teams;
Then you can create an array of teams:
Team league[] = {
{"FC Bayern Muenchen", 85, 27, 4, 2, 77, 16},
{"Borussia Dortmubd", 77, 24, 5, 4, 80, 32},
{"Bayer 04 Leverkusen", 57, 17, 6, 10, 53, 38},
{"Borussia M'Gladbach", 52, 16, 4, 13, 65, 50},
// ...
};
Then write a comparison function to obeys the definition used in qsort:
int compareTeams(const void *p1, const void *p2)
{
const Team *e1 = p1;
const Team *e2 = p2;
int dg1 = e1->gf - e1->gc;
int dg2 = e2->gf - e2->gc;
if (e1->points > e2->points) return -1;
if (e1->points < e2->points) return 1;
if (dg1 > dg2) return -1;
if (dg1 < dg2) return 1;
if (e1->gf > e2->gf) return -1;
if (e1->gf < e2->gf) return 1;
return 0;
}
and use it:
qsort(league,
sizeof(league) / sizeof(*league), // number of teams
sizeof(*league), // size of one team
compareTeams);
The restructuring means that the data for each team is kept together in the same struct and instead of swapping many independent arrays in order to keep them in sync, you swap whole teams.

Resources