Typecasting structure pointers - c

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.

Related

assign a nested structure pointer to a nested structure

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

Initialize recursive struct type in C properly

I am new to C programming and I have the following struct:
typedef struct _date {
char d[10], t[5], s[3];
struct _date *next;
} *date;
How can I properly create an instance of this?
My solution:
date neuerTermin(char *d, char *t, char *s, date cal) {
struct _date d = {*d, *t, *s, NULL};
date d_ptr = malloc(sizeof *d);
cal->next = d_ptr;
return d;
}
But I get an error: warning: initialization makes integer from pointer without a cast
You can do it as follows:
#include <stdio.h>
typedef struct _date {
char d[11], t[6], s[4]; // +1 to size for null-terminator ('\0')
struct _date *next;
} *date;
int main() {
struct _date a = { "15.07.2017", "16:00", "Foo", NULL };
date a_ptr = &a;
printf("Description: %s\nDate: %s\nTime: %s\n", a_ptr->s, a_ptr->d, a_ptr->t);
return 0;
}
The brace-enclosed, comma-separated list in the example above is the struct initializer.
To respond to the edits of your question, if you wish to dynamically allocate struct _date instances and initialize them in a function, then use malloc as follows:
date neuerTermin(const char* d, const char* t, const char* s) {
date cal = (date)malloc(sizeof(struct _date));
strncpy(cal->d, d, 10);
strncpy(cal->t, t, 5);
strncpy(cal->s, s, 3);
cal->next = NULL;
return cal;
}
In this case you have to fill the memory block pointed by cal member-by-member. Sample usage:
date root = neuerTermin("15.07.2017", "16:00", "Foo");
root->next = neuerTermin("27.07.2017", "10:00", "Bar");
root->next->next = neuerTermin("01.08.2017", "12:30", "Baz");
Important: if you used malloc to allocate memory, you have to deallocate it too with using free when you don't need it anymore.
While Akira has a very good answer for you (I voted for it), I would caution you about typedeffing pointers. Why? As your projects grow, when you start hiding levels of indirection behind a typedef, the level of confusion and potential for error grows.
If you need a pointer of a typedeffed type, declare an instance of one, but keep your typedefs to types so an not to mask levels of indirection.
You can do the same thing without hiding the level of indirection as follows:
#include <stdio.h>
typedef struct _date {
char d[11], t[6], s[4]; // +1 for '\0'
struct _date *next;
} date;
int main() {
date a = { "15.07.2017", "16:00", "Foo", NULL };
date *a_ptr = &a;
printf("Description: %s\nDate: %s\nTime: %s\n", a_ptr->s, a_ptr->d, a_ptr->t);
return 0;
}
Example Use/Output
PS> .\bin\structtypedef.exe
Description: Foo
Date: 15.07.2017
Time: 16:00
Typedeffing pointers is now wrong, it just creates pitfalls. See: In C, is it good form to use typedef for a pointer?.

Allocate memory for char array pointer of struct inside function

I was looking around for about one day on how to solve my problem. I find solutions for problems similar to mine but when I apply changes error : error: request for member 'mark' in something not a structure or union keeps showing.
What I have so far is a struct and I want to initialize it on a function call.
Edit my code:
typedef struct student * Student;
struct student {
char *mark; /* or array[2] like array[0] = 'A' , array[1] = 'B' */
int age;
int weight;
};
typedef enum{
MEMORY_GOOD,
MEMORY_BAD} Status;
int main(int argc, char* argv[]) {
int status = 0;
Student john
/* Function call to allocate memory*/
status = initMemory(&john);
return(0);
}
Status initMemory(Student *_st){
_st = malloc(sizeof(Student));
printf("Storage size for student : %d \n", sizeof(_st));
if(_st == NULL)
{
return MEMORY_BAD;
}
_st->mark = malloc(2*sizeof(char)); /* error: request for member 'mark' in something not a structure or union */
return MEMORY_GOOD;
}
Just replace
_st->mark = malloc(2 * sizeof(char));
With
(*_st)->mark = malloc(2 * sizeof(char));
_st is a pointer wich content is the address of the struct, so ...
1) first you need to dereference _st, and...
2) second, with the value you get, you point to the field mark
That's all !
try to avoid too many *s in your code,
was able to run it after making some changes, please refer to the ideone link in the next line.
http://ideone.com/Ow2D2m
#include<stdio.h>
#include<stdlib.h>
typedef struct student* Student; // taking Student as pointer to Struct
int initMemory(Student );
struct student {
char* mark; /* or array[2] like array[0] = 'A' , array[1] = 'B' */
int age;
int weight;
};
typedef enum{
MEMORY_GOOD,
MEMORY_BAD} Status;
int main(int argc, char* argv[]) {
Status status;
Student john; /* Pointer to struct */
/* Function call to allocate memory*/
status = initMemory(john);
printf("got status code %d",status);
}
int initMemory(Student _st){
_st = (Student)malloc(sizeof(Student));
printf("Storage size for student : %d \n", sizeof(_st));
if(_st == NULL)
{
return MEMORY_BAD;
} else {
char* _tmp = malloc(2*sizeof(char)); /* error: request for member 'mark' in something not a structure or union */
_st->mark = _tmp;
return MEMORY_GOOD;
}
}

Segmentation fault when I try to printf

Why am I getting a segmentationfault when it tries to print the second member in the list?
After printing the first element of the list, the debugger opens the stdio.h and says:
At C:\TDM-GCC-32\include\stdio.h:255
At C:\TDM-GCC-32\include\stdio.h:256
At C:\TDM-GCC-32\include\stdio.h:258
At C:\TDM-GCC-32\include\stdio.h:259
Here is the code.
#include <stdio.h>
#include <stdlib.h>
struct Student {
char *Name;
char *Adresse;
unsigned long Mtnr;
short Kurse;
struct Student *next;
struct Student *previous;
};
typedef struct Student Student;
Student *liste = NULL, *ende = NULL;
void add(char Name, char Adresse, unsigned long Mtnr, short Kurse) {
Student *add;
ende->next = malloc(sizeof(Student));
add = ende->next;
add->Name = Name;
add->Adresse = Adresse;
add->Mtnr = Mtnr;
add->Kurse = Kurse;
add->previous = ende;
add->next = NULL;
ende = ende->next;
}
void Ausgabe(Student *Anfang) {
while (Anfang != NULL) {
printf("%s %s %d %d \n", Anfang->Name, Anfang->Adresse, Anfang->Mtnr, Anfang->Kurse);
Anfang = Anfang->next;
}
}
int main() {
liste = malloc(sizeof(Student));
ende = liste;
liste->Name = "Anna Musterfrau";
liste->Adresse = "Am Schwarzberg-Campus 3";
liste->Mtnr = 22222;
liste->Kurse = 2;
liste->next = NULL;
liste->previous = NULL;
add("Hans Peter", "Kasernenstrasse 4", 4444, 4);
Ausgabe(liste);
return 0;
}
The error is in the declaration of the add() function. The strings should be char pointers, not chars.
void add(char *Name, char *Adresse, unsigned long Mtnr, short Kurse){
The signature of the function add is inconsistent to the declaration and usage to the members of Student. Change the signature as follows.
void add(char* Name, char* Adresse, unsigned long Mtnr, short Kurse)
On the long run, it might also be necessary to create copies of Name and Adresse in add, as the caller of add might deallocate them, perhaps causing undesired behaviour.
While Marc Is correct with his observation, there is one more thing you may want to fix here.
When you add a record, you allocate it, but you do not allocate the content of it's pointers (Specifically = for the name and address pointers). The add function just point them to the input's address. this is a problem because the data in the address supplied to the add function is likely to change if, for example, it's a user input, or some other external buffer.
in the code snipped below I fixed the 'name', but left the address as is. please run it and see what happens. (assaf's record displays david's address)
hope this helps
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student {
char *Name;
char *Adresse;
unsigned long Mtnr;
short Kurse;
struct Student *next;
struct Student *previous;
};
typedef struct Student Student;
Student *liste = NULL, *ende = NULL;
void add(char *Name, char *Adresse, unsigned long Mtnr, short Kurse) {
Student *add;
ende->next = malloc(sizeof(Student));
add = ende->next;
add->Name = malloc(strlen(Name)+1);
strcpy(add->Name, Name);
add->Adresse = Adresse;
add->Mtnr = Mtnr;
add->Kurse = Kurse;
add->previous = ende;
add->next = NULL;
ende = ende->next;
}
void Ausgabe(Student *Anfang) {
while (Anfang != NULL) {
printf("%s %s %d %d \n", Anfang->Name, Anfang->Adresse, Anfang->Mtnr, Anfang->Kurse);
Anfang = Anfang->next;
}
}
int main() {
char name_buf[100];
char address_buf[100];
liste = malloc(sizeof(Student));
ende = liste;
liste->Name = "Anna Musterfrau";
liste->Adresse = "Am Schwarzberg-Campus 3";
liste->Mtnr = 22222;
liste->Kurse = 2;
liste->next = NULL;
liste->previous = NULL;
add("Hans Peter", "Kasernenstrasse 4", 4444, 4);
sprintf(name_buf,"assaf stoler");
sprintf(address_buf,"maria 8");
add(name_buf, address_buf, 8888, 8);
sprintf(name_buf,"david david");
sprintf(address_buf,"some street 9");
add(name_buf, address_buf, 9999, 9);
Ausgabe(liste);
return 0;
}
EDIT: Op asked some questions, and the comment space is limited, so I'll add below:
A pointer is just an object pointing somewhere in memory. it's size is fixed. the content it's pointing to will vary.
When you include a pointer to a string in a structure, the space where the string is kept need to be allocated / accounted for. it is not part of the sizeof(struct).
In your original example the pointers were pointing to constant strings (which reside in the static code, usually the data section, allocated by the compiler), which is why your original code was able to access the strings.
In a more realistic case, the input data is not part of the program data, but is received by some input method (which my *buf was to emulate). as such, pointing your name and address at it would break the program, as the pointer you point to may have it's content changed. therefor copying of the data (string / array) is needed, and since we copy the data, we need to allocate space for it, and point our (name/address) pointer at it.
Alternate option is to use non-pointer array for name and address as in:
struct Student {
char Name[20];
char Adresse[60];
unsigned long Mtnr;
...
}
In this scenario, sizeof (struct Student) would actually include all the space for those fields. you still need to use strcpy or memcpy, as well as check for and handle strings that are too long to fit in your pre-defined length.
Hope this helps

C accessing array correctly

os-sim.h
typedef enum {
PROCESS_NEW = 0,
PROCESS_READY,
PROCESS_RUNNING,
PROCESS_WAITING,
PROCESS_TERMINATED
} process_state_t;
typedef struct _pcb_t {
const unsigned int pid;
const char *name;
const unsigned int static_priority;
process_state_t state; <<---Trying to access this
op_t *pc;
struct _pcb_t *next;
} pcb_t;
file1.c
static pcb_t **current;
extern void yield(unsigned int cpu_id)
{
/* FIX ME */
while (1)
{
pthread_mutex_lock(&current_mutex);
current[cpu_id].state = PROCESS_WAITING; ///<-------ERROR HERE
pthread_mutex_unlock(&current_mutex);
break;
}
schedule(cpu_id);
}
in main method():
current = malloc(sizeof(pcb_t*) * 10);
I have error in this line current[cpu_id].state = PROCESS_WAITING;
error: request for member ‘state’ in something not a structure or union
What does this error mean?
Is this not the right way to access current array which holds pcb_t?
If so, how do i access the current array? and state field?
You're likely looking for:
current[cpu_id]->state = PROCESS_WAITING;
The type of current is pcb_t **. So the type of current[cpu_id] is pcb_t *.

Resources