assign a nested structure pointer to a nested structure - c

I've one solid structure and another structure with pointers. The purpose of program is to assign: solid structure to structure with pointers and access each solid structure member using other structure pointer.
I've problem statement: as two structure member as not symmetric, when i assign solid structure address to structure with pointers, member pointer initialization go bad and crash the system.
Does anyone have any approach to find a solution for this problem in an optimized way?
----------------------------------------------------------------------- program -----------------------------
#include <stdio.h>
#include <string.h>
#include <stddef.h>
/* ===================== Binding Structure ================================= */
typedef struct
{
char id;
}tmodel;
typedef struct
{
char id;
}tbrand;
typedef struct
{
char id;
}tcommercialRef;
typedef struct
{
char id;
}tserialnum;
typedef struct
{
tmodel *smodel;
tbrand *sbrand;
tcommercialRef *scommref;
tserialnum *sslnum;
}tmetadata;
typedef struct
{
tmetadata *smetadata;
}tlink;
typedef struct
{
tlink *slink;
}trefernce;
typedef struct
{
char id[10];
int ttl;
int tss;
trefernce *sref;
}telectrical;
/* ===================== Application Strucuture ==============================*/
void filldata(telectrical *elec);
typedef struct
{
tmodel smodel;
tbrand sbrand;
tcommercialRef scommref;
tserialnum sslnum;
}Ymetadata;
typedef struct
{
Ymetadata smetadata;
}slink;
typedef struct
{
slink glink;
}refernce;
typedef struct
{
char id[10];
int ttl;
int tss;
refernce grefernce;
}gtelectrical;
//solid strucutre object
gtelectrical obj;
//structure pointer object
telectrical *elec = {0};
/* =============================== main.c =================================== */
int main()
{
printf("test");
//static void **p = (void *)&elec;
obj.tss = 55;
obj.ttl = 100;
obj.grefernce.glink.smetadata.smodel.id = 5;
obj.grefernce.glink.smetadata.sbrand.id = 6;
obj.grefernce.glink.smetadata.scommref.id = 7;
obj.grefernce.glink.smetadata.sslnum.id = 8;
elec = (telectrical *)&obj;
//elec structure -> sref pointer goes bad as it's not same type as "grefernce"
//*p = (void *)&obj;
//static long x = (long) offsetof( telectrical, sref);
//(long) offsetof(struct telectrical, sref);
//*(*p + x) = obj.grefernce.glink.smetadata.;
elec->id[0] = 0;
elec->id[1] = 1;
elec->id[2] = 2;
elec->ttl = 5;
elec->tss = 10;
elec->sref->slink->smetadata->sslnum->id = 4;
elec->sref->slink->smetadata->sbrand->id = 1;
elec->sref->slink->smetadata->scommref->id = 2;
elec->sref->slink->smetadata->smodel->id = 3;
//filldata(elec);
printf("------");
printf("%d\n",elec->sref->slink->smetadata->sslnum->id);
printf("%d\n",elec->sref->slink->smetadata->sbrand->id);
printf("%d\n",elec->sref->slink->smetadata->scommref->id);
printf("%d\n",elec->sref->slink->smetadata->smodel->id);
return 0;
}
/* //////////////////////////////////////// user scope ////////////////////////////// */
void filldata(telectrical *pelec)
{
pelec->id[0] = 0;
pelec->id[1] = 1;
pelec->id[2] = 2;
pelec->ttl = 5;
pelec->tss = 10;
//pelec->sref->slink->smetadata->sslnum->id = 4;
//pelec->sref->slink->smetadata->sbrand->id = 1;
//pelec->sref->slink->smetadata->scommref->id = 2;
//pelec->sref->slink->smetadata->smodel->id = 3;
}

You are not assigning memory for the pointers to other struct present inside another struct. Here is something which might help you in multi-level memory allocation and assignment:
#include<stdio.h>
#include<stdlib.h>
typedef struct A
{
int i;
}A_Node;
typedef struct B
{
A_Node *A_ptr;
}B_Node;
typedef struct C
{
B_Node *B_ptr;
}C_Node;
int main(void)
{
//ACCESSING-MANIPULATING A USING B
B_Node B_obj;
B_obj.A_ptr=malloc(sizeof(*(B_obj.A_ptr)));
(B_obj.A_ptr)->i=192;
A_Node A_obj=*(B_obj.A_ptr); //For checking if the allocation is successful and good
printf("%d\n",A_obj.i);
//ACCESSING-MANIPULATING A USING C
C_Node C_obj;
C_obj.B_ptr=malloc(sizeof(*(C_obj.B_ptr))); //allocating space for struct of B using C object
(C_obj.B_ptr)->A_ptr = malloc(sizeof(*((C_obj.B_ptr)->A_ptr))); //allocating space for struct of A using B Struct for which space was allocated in previous step by C struct
((C_obj.B_ptr)->A_ptr)->i=876;
A_obj=*((C_obj.B_ptr)->A_ptr); //For checking if the allocation is successful and good
printf("%d\n",A_obj.i);
return 0;
}
Read the code and ask if there are any doubts, in the similar way this multi-level struct-inside-struct can be created (though it would be ugly).

Related

Dynamic Memory allocation of array inside structure in C

I'm doing dining-philosopher problem in C for assignment. And got stuck very begining of my code.
I decided each philosopher to be structure, and forks to be int array.
But I can't use global variable in this assignment.
So, I have to include shared variable in philosopher structure to pass them for arguments of thread routine.
Here is my problem - how to include int array in structure if I can't know proper size of them when initializing?
My plan is just include pointer variable in structure then allocate array's address using &.
But It doesn't work :
#include <stdlib.h>
/* inside structure*/
typedef struct s_share {
int **forks;
} t_share;
/* outside structure */
typedef struct s_philo {
t_share *share;
} t_philo;
int main(void)
{
t_philo *philo;
int *forks;
int i;
i = 0;
/* malloc structure arrary philo, size = 10 */
philo = (t_philo *)malloc(sizeof(t_philo) * 10);
/* malloc int arrary forks, size = 100 */
forks = (int *)malloc(sizeof(int) * 100);
while (i < 10)
{
philo[i].share->forks = &forks; //error
i++;
}
}
Output : segmentation fault
I tested share->forks size like this :
printf("size of forks : %ld\n", sizeof(philo->share->forks));
Output was 8.
It's enough size to store int * pointer.
Through this I know It's not the memory allocation problem.
Then what is problem? Can someone check this for me?
Edit :
When I try to malloc directly philo->share->forks, I got same error.
typedef struct s_share {
int *forks;
} t_share;
typedef struct s_philo {
t_share *share;
} t_philo;
int main(void)
{
t_philo *philo;
int *forks;
int i;
i = 0;
philo = (t_philo *)malloc(sizeof(t_philo) * 10);
while (i < 10)
{
philo[i].share->forks = (int *)malloc(sizeof(int) * 100); //error
i++;
}
}
I thought it's because when philo initialized, sizeof operator calculated forks's memroy to be 8 - which required for pointer.
Is there something wrong?
Edit 2 :
To clear my question,
It's easy to solve this problem, if I write size of array in structure definition.
typedef struct s_share {
int forks[100];
} t_share;
typedef struct s_philo {
t_share *share;
} t_philo;
but according to my assignmet I have to get philosopher's number from cmd. So I can't do that.
Above is simple version of my origin code
Sorry, Edit 2 is wrong :
typedef struct s_share {
int forks[100];
} t_share;
typedef struct s_philo {
t_share *share;
} t_philo;
int main(void)
{
t_philo *philo;
t_share *share;
int *forks;
int i;
i = 0;
philo = (t_philo *)malloc(sizeof(t_philo) * 10);
while (i < 10)
{
philo[i].share->forks[i] = 1;
i++;
}
}
Output
zsh: segmentation fault ./a.out
I still got segfault when I write array size in struct definition.
I used calloc to initialize all member in my struct but same error occurs :
typedef struct s_share {
int **forks;
} t_share;
typedef struct s_philo {
t_share *share;
} t_philo;
int main(void)
{
t_philo *philo;
t_share *share;
int *forks;
int i;
i = 0;
philo = (t_philo *)calloc(10, sizeof(t_philo));
forks = (int *)calloc(100, sizeof(int));
while (i < 10)
{
philo[i].share->forks = &forks; //error
i++;
}
}
Edit 4:
I finally found error. It's because I didn't malloc 'share' struct in philo struct
typedef struct s_share {
int **forks;
} t_share;
typedef struct s_philo {
t_share *share;
} t_philo;
int main(void)
{
t_philo *philo;
int *forks;
int i;
i = 0;
philo = (t_philo *)malloc(sizeof(t_philo) * 10);
forks = (int *)malloc(sizeof(int) * 100);
while (i < 10)
{
philo[i].share = (t_share *)malloc(sizeof(t_share)); //here
philo[i].share.forks = &forks;
i++;
}
}
That one line -allocating struct share- solved problem.
Or, I can modify philo struct definition like this :
typedef struct s_philo {
t_share share; //not pointer, just struct
} t_philo;
In this way, I can automatically malloc struct share.
I got confused in this point. Thanks for helping!
this line
philo[i].share->forks
Is dereferencing the pointer 'share' which is not set. You called malloc and did not set any values, so the data inside your allocated buffer is 'garbage' data.
// add begin
t_share* new_share = (t_share*)malloc(sizeof(t_share));
philo[i].share = new_share;
// add end
// don't use &forks
philo[i].share->forks = forks; //error
i++;
// need forks++
forks++;

Pointer in const C struct

Assuming that the following structures exist...
typedef struct MyFirstStruct
{
uint8_t someContent;
}
typedef struct MySecondStruct
{
MyFirstStruct* firstStructs;
uint8_t firstStructCount;
}
... and a function gets the following Parameter.
const MySecondStruct* const secondStruct
Is it allowed to change any value?
I am sure that this is not correct:
secondStruct->firstStructCount++.
But neither the Compiler nor PC-Lint complains about secondStruct->firstStructs->someContent++.
Is it allowed to do Change someContent because firstStructs is not const or is the behavior undefined?
Thanks!
The values of the nested struct(s) firstStructs can change as long as the pointer does not change. The constness of the pointer prevents the pointer value from changing, but the constness of the struct only means that its values must not change (i.e. the value of the pointer and the count).
You can modify the struct(s) pointed to by firstStructs arbitrarily without changing the pointer. You can also clearly see from the struct definition that this is legal, because firstStructs is a pointer to struct MyFirstStruct, not a pointer to const struct MyFirstStruct.
Here is an example to understand the principle without the const-pointer to const elements:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int x;
} Simple;
typedef struct {
Simple* s;
int scount;
} Nested;
int main()
{
Nested x;
x.scount = 10;
x.s = malloc(sizeof(Simple) * x.scount);
const Nested n = x;
for (int i = 0; i < n.scount; ++i)
{
n.s[i].x = i;
printf("%d\n", n.s[i].x);
}
}
It is OK and it was easy to check yourself:
typedef struct
{
uint8_t someContent;
} MyFirstStruct;
typedef struct
{
MyFirstStruct* firstStructs;
uint8_t firstStructCount;
}MySecondStruct;
MyFirstStruct fs;
MySecondStruct str = {.firstStructs = &fs};
const MySecondStruct* const secondStruct = &str;
int main()
{
secondStruct->firstStructs->someContent++;
}
but did not as the posted code was full of syntax errors.
You cant of course change the pointer itself:
This will give you errors:
typedef struct
{
uint8_t someContent;
} MyFirstStruct;
typedef struct
{
MyFirstStruct* firstStructs;
uint8_t firstStructCount;
}MySecondStruct;
MyFirstStruct fs[2];
MyFirstStruct ss;
MySecondStruct str = {.firstStructs = fs};
const MySecondStruct* const secondStruct = &str;
int main()
{
secondStruct->firstStructs++->someContent++;
secondStruct->firstStructs = &ss;
}

Typecasting structure pointers

Hie guys. I am studying structures and pointers using the book called Pointers in C: A Hands on Approach and on page 107, I came across an incomplete example of struct type casting. I tried to make it work by just implementing the function receivedata() ,adding headers and making a few changes.
This is the complete code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct signature
{
char sign;
char version;
};
struct id
{
char id;
char platform;
};
struct data
{
struct id idv;
struct signature sig;
char data[100];
};
static void receivedata(struct data *d);
static struct signature *extractsignature(struct data *d);
static struct id *extractid(struct data *d);
int main(int argc, char *argv[])
{
/* Actual line in book is :
* struct data *img; with no memory allocation or assignment to NULL.
* Had errors so i allocated memory on the heap before passing the value to
* Receivedata(); */
struct data *img = malloc(sizeof(struct data));
receivedata(img);
/* Actual line in book is :
* struct id *idval = extractid(&img);
* struct signature *sig = extractsignature(&img);
* This is obviously erroneous because &img is a pointer
* to a pointer (struct data**) which is not the data type for
* the extract functions' argument */
struct id *idval = extractid(img);
struct signature *sig = extractsignature(img);
printf("For signature:\n");
printf("sign = %c", sig->sign);
printf(" version = %c\n\n", sig->version);
printf("For id:\n");
printf("id = %c", idval->id);
printf(" platform = %c", idval->platform);
printf("\ndata = %s", img->data);
return 0;
}
static struct signature *extractsignature(struct data *d)
{
struct signature *sig = (struct signature *)d;
return sig;
}
static struct id *extractid(struct data *d)
{
struct id *idv = (struct id *)d;
return idv;
}
static void receivedata(struct data *d)
{
struct data *dptr = d;
char *ch = "CODING IS COOL!";
dptr->sig.sign = 's';
dptr->sig.version = '1';
dptr->idv.id = 'i';
dptr->idv.platform = 'p';
strncpy(dptr->data, ch, strlen(ch));
return;
}
What I would like to understand is the casting inside the function extractid() and extraxtsignature() because it seems we are casting struct data * so as to retrieve its individual members. I ran the program and what i get is the value of the first member of struct data for both sig member and id members. Here is the output when struct id comes first in the struct data:
For signature:
sign = i version = p
For id:
id = i platform = p
data = CODING IS COOL!
and this when struct signature is the first element:
For signature:
sign = s version = 1
For id:
id = s platform = 1
data = CODING IS COOL!
and finally, this when char data[100] is the first element:
For signature:
sign = C version = O
For id:
id = C platform = O
data = CODING IS COOL!
May you please explain this type of casting, when to use it and the best practices. Thank you very much.
struct data
{
struct id idv;
struct signature sig;
char data[100];
};
For the above definition, the extractid function below is valid and will get right results.
static struct id *extractid(struct data *d)
{
struct id *idv = (struct id *)d;
return idv;
}
This is because, struct id is the first member of the struct data. So, when you have struct data *d, the d points to the starting address of struct data and which is same as the starting address of the first member struct id.
So, if you are casting for the first member of the struct, then it is right as per the code you have provided above.

How to allocate memory with different type in C?

I have the following code in C:
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
int student[1];
} People;
#define NUM_OF_PEOPLE
void *p = malloc(sizeof(People) + sizeof(int) * NUM_OF_PEOPLE + sizeof(Student) * NUM_OF_PEOPLE);
How could I find the pointer to the memory point to the first element of struct Student in the memory?
I try to do it in the following way:
int i = 0;
for(i = 0; i < NUM_OF_PEOPLE; i++)
{
Student * student_p = p.student[NUM_OF_PEOPLE];
}
It does not work, so can we allocate memory in the way?
And how to find the first element of struct Student in the memory?
What you have is an ancient way of having a flexible array member, which was technically also undefined behavior.
You are looking for this.
First, you need to define your struct like this (I don't know what the ints before the Students are, so let's just call it id):
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
Student student;
} StudentAndId;
typedef struct
{
int id;
StudentAndId students[];
} People;
Note the lack of size in the array inside People. Now you do this:
People *p = malloc(sizeof(People) + sizeof(StudentAndId[NUM_OF_PEOPLE]));
Then you can access students inside p as if it was an array of NUM_OF_PEOPLE elements.
Remember to compile with C99 (or C11) support. With gcc that would be -std=c99 or -std=gnu99.
This will allocate memory for storing the date but how you access it depends on how you store date. using C pointers you can store and access data using this structure and allocation but accessing the members will not be direct. it will involve pointer arithmetic. So better to use other structure if possible. If using this way of allocation then you need to do pointer arithmetic to get the next elements.
Try this:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
int student[1];
} People;
#define NUM_OF_PEOPLE 10
int main()
{
People *p = malloc(sizeof(People) + sizeof(int) * NUM_OF_PEOPLE + sizeof(Student) * NUM_OF_PEOPLE);
int* id = (int*)(p+1);
Student* s = (Student*)(id+NUM_OF_PEOPLE);
printf("Size of People : %d\n", sizeof(People));
printf("p points to : %p\n", p);
printf("id points to : %p\n", id);
printf("s points to : %p\n", s);
}
Here's a sample output:
Size of People : 8
p points to : 0x80010460
id points to : 0x80010468
s points to : 0x80010490
You may want to add the id field to your Student data structure, e.g.:
typedef struct {
int id;
int age;
int phoneNumber;
} Student;
Then, you can define a structure having a fixed header (in this case, this can be the number of students), followed by a variable-sized array of Students:
#define ARRAY_OF_ANY_SIZE 1
typedef struct {
int count;
Student students[ARRAY_OF_ANY_SIZE];
} People;
This blog post explains this technique of having "arrays of size 1", including a discussion of the alignment problem.
I won't repeat the original blog post code here. Just consider that you can use the portable offsetof() instead of the Windows-specific FIELD_OFFSET() macro.
As a sample code, you may want to consider the following:
#include <stdio.h> /* For printf() */
#include <stddef.h> /* For offsetof() */
#include <stdlib.h> /* For dynamic memory allocation */
typedef struct {
int id;
int age;
int phoneNumber;
} Student;
#define ARRAY_OF_ANY_SIZE 1
typedef struct {
int count;
Student students[ARRAY_OF_ANY_SIZE];
} People;
int main(int argc, char* argv[]) {
People* people;
const int numberOfStudents = 3;
int i;
/* Dynamically allocate memory to store the data structure */
people = malloc(offsetof(People, students[numberOfStudents]));
/* Check memory allocation ... */
/* Fill the data structure */
people->count = numberOfStudents;
for (i = 0; i < numberOfStudents; i++) {
people->students[i].id = i;
people->students[i].age = (i+1)*10;
people->students[i].phoneNumber = 11000 + i;
}
/* Print the data structure content */
for (i = 0; i < people->count; i++) {
printf("id: %d, age=%d, phone=%d\n",
people->students[i].id,
people->students[i].age,
people->students[i].phoneNumber);
}
/* Release the memory allocated by the data structure */
free(people);
return 0;
}
Output:
id: 0, age=10, phone=11000
id: 1, age=20, phone=11001
id: 2, age=30, phone=11002

C (not ++) a struct of struct array in struct dynamic initialization troubles malloc

I have a small trouble initializing (dynamic) parts of my structures that are in an array. This is what i have so far I am using a sub-routine to create the struct
t_grille_animaux creer_grille(int dim_ligne, int dim_col)
{
t_grille_animaux grille;
grille.la_grille = (t_case_animal **) malloc(sizeof(t_case_animal)*dim_ligne*dim_col);
grille.dim_colonne = dim_col;
grille.dim_ligne = dim_ligne;
grille.nb_predateurs = NULL;
grille.nb_proies = NULL;
return grille;
}
This is my structure:
typedef struct
{
t_case_animal ** la_grille; //2D array
int dim_ligne;
int dim_colonne;
int nb_proies;
int nb_predateurs;
} t_grille_animaux;
typedef struct
{
t_contenu etat;
t_animal animal;
} t_case_animal;
typedef enum {VIDE, PROIE, PREDATEUR} t_contenu;
typedef struct
{
int age;
int jrs_gestation;
int energie;
int disponible;
} t_animal;
(Sorry for the language)
What I get right now is that everything that isn't the struct in the array is fine. But everything in the array is undeclared.
This should do the trick:
#define NUM_ROWS (10)
#define NUM_COLS (15)
grille.la_grille = malloc(NUM_ROWS * sizeof(*grille.la_grille));
for(int row = 0; row < NUM_ROWS; row++)
grille.la_grille[row] = malloc(NUM_COLS * sizeof(**grille.la_grille));
The malloc() function does not (necessarily) initialise the allocated bytes to any value in particular. So after calling malloc(), you should explicitly initialise the allocated data.
Having said that, you have a couple of choices about how you can store your two-dimensional array. It depends on how you want to access the data. Since C does not have true multidimensional arrays, you can either:
declare a single dimension array of size dim_ligne*dim_col of t_case_animal values
declare an array of row pointers of size dim_ligne that each point to another single dimensional array of dim_col values
For the first case, change your declaration of la_grille to:
t_case_animal * la_grille;
and access your values as something like la_grille[j*dim_colonne+i].
For the second case, be sure to initialise your subarrays:
grille.la_grille = (t_case_animal **) malloc(sizeof(t_case_animal*)*dim_ligne);
for (int i = 0; i < dim_ligne; i++) {
grille.la_grille[i] = (t_case_animal *) malloc(sizeof(t_case_animal)*dim_col);
}
In the second case, you would access your values as something like la_grille[j][i].
You can use malloc() to allocate memory for each row. The following code should work:
#include<stdlib.h>
typedef struct
{
int age;
int jrs_gestation;
int energie;
int disponible;
}t_animal;
typedef enum {VIDE, PROIE, PREDATEUR} t_contenu;
typedef struct
{
t_contenu etat;
t_animal animal;
} t_case_animal;
typedef struct
{
t_case_animal ** la_grille; //2D array
int dim_ligne;
int dim_colonne;
int nb_proies;
int nb_predateurs;
} t_grille_animaux;
t_grille_animaux creer_grille(int dim_ligne,int dim_col)
{
t_grille_animaux grille;
grille.la_grille = (t_case_animal**) malloc(sizeof(t_case_animal*)*dim_ligne);
for(int i=0; i<dim_ligne; i++) {
grille.la_grille[i] = (t_case_animal*) malloc(sizeof(t_case_animal)*dim_col);
}
grille.dim_colonne = dim_col;
grille.dim_ligne = dim_ligne;
grille.nb_predateurs = 0;
grille.nb_proies = 0;
return grille;
}
int main(int argc, char* argv[])
{
t_grille_animaux test;
test = creer_grille(3, 4);
}

Resources