I have an assignment that is making me lose valuable hours without success. I have to read the contents from a struct that is passed to a function as void *c. I can read its contents without problems except the field that is a pointer to another struct. Example code:
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct Car Car;
struct Car {
int year;
int type;
int free;
struct {
char *name;
char *city;
} *facility;
};
int main()
{
Car *c = malloc(sizeof(Car)*2);
c->year = 2020;
c->type = 2;
c->free = 1;
c->facility = malloc(200);
c->facility->name = malloc(10);
c->facility->city = malloc(10);
snprintf(c->facility->name, 5, "Test");
snprintf(c->facility->city, 5, "Test");
test(c);
}
int test(void *c)
{
int year = *(void **) c;
int type = *(void **) (c+4);
int free = *(void **) (c+4+4);
printf("Year %d\n",year);
printf("Type %d\n",type);
printf("Free %d\n",free);
void *facility;
facility = *(void **) (c+4+4+4);
printf("Facility name %s", *(void **) facility);
printf("Facility city %s", *(void **) facility+8);
}
The part I am unable to read is facility name and facility city. I know I can access easily using -> but the assignment asks precisely understand how structure is defined in memory and extract its contents directly using the void*. Thanks.
the assignment asks precisely understand how structure is defined in memory
The memory layout (assuming no padding) would look something like the following.
-------------------------|
| ^ |
c ------> | year | sizeof(int) |
| v |
|------------------------|
| type |
|------------------------|
| free |
|------------------------| |--------| |---|---|---
| facility | ------> | name | -------> | a | b | ..
|------------------------| |--------| |---|---|---
| city | ---\
|--------| | |---|---|---
\---> | x | y | ..
|---|---|---
To access what would be c->facility->city
, for example:
void *facility = *(void **)( (char *)c + 3 * sizeof(int) ); // skip past year, type, free
void *city = *(void **)((char *)facility + sizeof(char *)); // skip past name
[ EDIT ] Without the "no padding" assumption, the code could use the offsetof
macro, instead.
void *facility = *(void **)( (char *)c + offsetof(struct Car, facility) );