Void * that saves different structs - c

typedef struct s_list
{
void *content;
struct s_list *next;
} t_list;
typedef struct s_env
{
char *key;
char *val;
struct s_env *next;
} t_env;
typedef struct s_heredoc
{
char *term;
char *delimiter;
char *heredoc;
} t_heredoc;
typedef struct s_cmd
{
char *cmd;
char *path;
int istream;
int ostream;
} t_cmd;
typedef struct s_table{
char **paths;
char **reserved;
char *cmdline;
t_list *cmds;
} t_table;
I have a general struct t_table which have a pointer to t_list struct called cmds.
How can i save different structs for example t_env, t_heredoc, t_cmd in void * content; property of t_list struct. How should I cast the void * content to another type (t_env, t_cmd, t_heredoc, etc)
void lexical_analyze(char *cmdline, t_table **table)
{
cmdline = openquotes(cmdline);
cmdline = find_replace(cmdline, (*table)->env);
(*table)->cmds = malloc(sizeof(t_list));
}
After this point i can’t understand how to cast and how to allocate a memory for the other structs for example t_cmd struct

You can assign a pointer to any struct to your context member. But if you want to use that struct later, you will need to recover the original pointer type. That means you must store extra information about type of your content in your struct:
typedef enum {
CT_Env,
CT_Cmd,
CT_HereDoc
} t_context_type;
typedef struct s_list
{
void *content;
t_context_type type;
struct s_list *next;
} t_list;
t_list *add_Env(t_env *env)
{
t_list *list = malloc(sizeof *list);
... Do the list handling...
list->context = env;
list->type = CT_Env;
return list;
}
Then, when you want to access the nodes of your list you can cast to correct type:
void handle_node(t_list *list)
{
switch (list->type)
{
case CT_Env:
{
t_env *env = list->context;
// Access members of t_enf via env pointer
}
break;
case CT_Cmd: // TODO handle t_cmd type
break;
case CT_HereDoc: // TODO handle t_heredoc type
break;
default: // TODO: Error handling
break;
}
}
Of course that code is not complete. It should show how it is supposed to work.

Related

struct that holds struct, how to dereference

i have couple of linked lists in my larger program which i now want to keep in a struct (t_holder).
typedef struct s_list
{
int val;
struct t_list *next;
} t_list;
typedef struct s_holder
{
t_list *a_starts;
// more lists...
} t_holder;
now i try to figure out how i dereference this in my program.
void try_out(t_holder *list_holder, int num)
{
//assigning something to a_starts
list_holder->a_starts->val = num;
}
int main(int argc, char *argv[])
{
t_holder *list_holder;
int num;
num = 42;
list_holder = NULL;
try_out(list_holder, num);
return (0);
}
in the function "try_out" i simlpy try to assign a value to a_starts->val but my debugger shows me ACCESS_ERROR if i declare it like this
list_holder->a_starts->val = num;
For starters this typedef declarations
typedef struct s_list
{
int val;
struct t_list *next; // <===
} t_list;
is incorrect. It seems you mean
typedef struct s_list
{
int val;
struct s_list *next; // <===
} t_list;
As for your other code then you declared a null pointer
t_holder *list_holder;
//...
list_holder = NULL;
So dereferencing the null pointer results in undefined behavior.
You need to write something like the following
t_holder list_holder = { .a_starts = NULL };
//...
try_out( &list_holder, num);
and then within the function something like
void try_out(t_holder *list_holder, int num)
{
t_list *node = malloc( sizeof( *node ) );
node->val = num;
node->next = list_holder->a_starts;
list_holder->a_starts = node;
}

Overloading with struct in C

I am trying to write a function with the same name, but that accepts 3 different typers of structs.I don't know how I can write the parameters to do this.So in the _______, there should be proffesore, amminustratore, studente. Sp that the function can accept all 3 types of struct but only one at the time.
Here is the code:
int confermaCredenziali(struct ______ dati, char *uN, char *pW);
struct amministratore{
char userName[MAX_LNG];
char passWord[MAX_LNG];
int stato;
struct ammin *next;
};
struct professore{
int ID;
char userName[MAX_LNG];
char passWord[MAX_LNG];
int stato;
struct prof *next;
};
struct studente{
int ID;
char *userName[MAX_LNG];
char *passWord[MAX_LNG];
int punti;
int stato;
struct studente *next;
};
int confermaCredenziali(struct ______ dati, char *uN, char *pW){
while (dati != NULL) {
if (strcmp(dati->userName, uN) == 0 && strcmp(dati->passWord, pW) == 0){
if (dati->stato == 1)
return 1;
else{
printf("Il suo stato e' passivo.\n");
return 0;
}
}
dati = dati->next;
}
printf("Credeziali errate.\n");
return 0;
}
I suggest a single struct type like this
typedef struct person {
char userName[MAX_LNG];
char passWord[MAX_LNG];
int stato;
struct person *next;
} person_t;
Then you have three linked lists
person_t *amministratore = NULL;
person_t *professore = NULL;
person_t *studente = NULL;
Also, the function needs a pointer argument, I suggest
int confermaCredenziali(person_t *dati, char *uN, char *pW)
Then you pass the head of the linked list you have selected, to the function. It works with one list at a time, and the three lists are completely separate.
As stated earlier in comments:
Create as follows:
Include all three struct as members of a union.
add the union as a member of a collector struct.
Add an additional enum member to the collector struct to identify which of the three struct you are passing.
The following illustrates:
typdef enum {
ADMIN,
PROF,
STUD,
MAX_S
}S_TYPE;
typedef struct {
...
}amministratore;
typedef struct {
...
}professore;
typedef struct {
...
}studente;
typedef union{
administratore admin;
professore prof;
studente stud;
}s_union;
typedef struct {
s_union;
S_TYPE type;
}collector;
Your prototype would be modified to:
int confermaCredenziali(collector *c, S_Type type, dati, char *uN, char *pW);
As mentioned also in comments, the argument for this struct as passed in the prototype should be as pointer, so that the members can be changed, and for efficiency, as a pointer is often times smaller than the entire struct
this example is trivial but you can do something like this:
enum type{STUD = 0, PROF, ADMIN};
int confermaCredenzialiSTUD(void *dati, char *uN, char *pW);
int confermaCredenzialiPROF(void *dati, char *uN, char *pW);
int confermaCredenzialiADMIN(void *dati, char *uN, char *pW);
const int (*credenziali[3])(void *, char *, char *) =
{confermaCredenzialiSTUD, confermaCredenzialiPROF, confermaCredenzialiADMIN};
int confermaCredenziali(enum type t, void *dati, char *uN, char *pW)
{
return redenziali[t](dati, uN, pW);
}
and in the functions do correctly what you need for the particular type.

Convert struct with dynamic arrays to double pointers

I had a data structure, which contain some dynamic sized fields.
I.e. void *methods[0] I also declared them as void *methods[], but this seems also wrong, because this shouldn't be the only field in the struct.
This structure is only to read memory which is defined somewhere else, so I can't just add the size of methods inside itable_t/itt_t and define methods/entries as dynamic.
The code below works, but give me some warnings which I don't want.
struct itable_t {
void *methods[0];
};
typedef struct itable_t itable_t;
struct itt_entry_t {
itable_t *itable;
void *id;
int32_t prev;
int32_t next;
};
typedef struct itt_entry_t itt_entry_t;
struct itt_t {
itt_entry_t entries[0];
};
typedef struct itt_t itt_t;
struct vtable_t {
rtti_t *rtti;
itt_t *itt;
void *dynamic_methods[];
};
typedef struct vtable_t vtable_t;
struct object_t {
vtable_t *vptr;
};
typedef struct object_t object_t;
So I tried to translate the structure to the following, which doesn't seems to be correct, because I get some segmentation faults
struct itt_entry_t {
void **itable;
void *id;
int32_t prev;
int32_t next;
};
typedef struct itt_entry_t itt_entry_t;
struct vtable_t {
rtti_t *rtti;
itt_entry_t **itt;
void *dynamic_methods[];
};
typedef struct vtable_t vtable_t;
struct object_t {
vtable_t *vptr;
};
typedef struct object_t object_t;
How should I define and access my structs, so that they work?
EDIT: How the structure is currently used:
The function is called from assembler
movl %edi, (%esp)
movl $itable_table_name_815, 4(%esp)
movl $0x4, 8(%esp)
call oo_searched_itable_method
c function
void *oo_searched_itable_method(const object_t *obj, void *interface_id, int32_t offset)
{
itt_t *itt = obj->vptr->itt;
int32_t i = 1;
do {
if (itt->entries[i].id == interface_id) {
return itt->entries[i].itable->methods[offset];
}
}
while (itt->entries[++i].id != NULL);
// should never happen
abort();
}
I solved the problem now with the following code - thanks for any help and good suggestions I got in the comments.
structure definition:
struct itt_entry_t {
void **itable;
void *id;
int32_t prev;
int32_t next;
};
typedef struct itt_entry_t itt_entry_t;
struct vtable_t {
rtti_t *rtti;
itt_entry_t *itt;
void *dynamic_methods[];
};
typedef struct vtable_t vtable_t;
struct object_t {
vtable_t *vptr;
};
typedef struct object_t object_t;
code which uses the structurs
void *oo_searched_itable_method(const object_t *obj, void *interface_id, int32_t offset) {
itt_entry_t *itt = obj->vptr->itt;
int32_t i = 1;
do {
if (itt[i].id == interface_id) {
return itt[i].itable[offset];
}
}
while (itt[++i].id != NULL);
fprintf(stderr, "ITable not found...");
abort();
}
According to me, i declare structures like that :
typedef struct s_data
{
char *str;
int foo;
} t_data;
Now in your code you need to declare it by this way :
t_data my_struct;
my_struct.foo = 8;
my_struct.str = malloc(4 * sizeof(char));
my_struct.str = strcpy(my_struct.str, "foobar");
But i need more informations from you, what are the warnings and show me how you declare and access your structure.

Dereferencing pointer to incomplete type

I am new to C programming and as a mini project I decided to try to implement a stack in C using OOP style structure in a file GenericStack.h as shown below:
void _GENERICSTACK0001(void *,void *);
void *_GENERICSTACK0002(void *);
int _GENERICSTACK0003(void *);
typedef struct
{
struct GenericStackNode *next;
void *data;
int type;
}GenericStackNode;
typedef struct
{
struct GenericStackNode *top;
int count;
void (*add)(void *,void *);
void *(*pop)(void *);
int (*hasNext)(void *);
int (*getCount)(void *);
}GenericStack;
GenericStack newGenericStack()
{
GenericStack *genStack = malloc(sizeof(GenericStack));
genStack->add = _GENERICSTACK0001;
genStack->pop = _GENERICSTACK0002;
genStack->hasNext = _GENERICSTACK0003;
genStack->getCount = _GENERICSTACK0003;
genStack->top=NULL;
genStack->count = 0;
return *genStack;
}
void _GENERICSTACK0001(void *self,void *data)//add
{
GenericStack *genStack = self;
if(genStack->top == NULL)
{
genStack->top = malloc(sizeof(GenericStackNode));
genStack->top->next = NULL;
genStack->top->type = 0;
genStack->top->data = data;
}
else
{
GenericStackNode *temp = malloc(sizeof(GenericStackNode));
temp->next = genStack->top;
temp->type = 0;
temp->data = data;
genStack->top = temp;
genStack->count++;
}
}
void *_GENERICSTACK0002(void *self)//pop
{
GenericStack *genStack = self;
void *data = NULL;
if(genStack->top == NULL)
{
return data;
}
else
{
GenericStackNode *temp = genStack->top;
genStack->top = genStack->top->next;
data = temp->data;
free(temp);
genStack->count--;
return data;
}
}
int _GENERICSTACK0003(void *self)
{
GenericStack *genStack = self;
return genStack->count;
}
All I need to know is why (among many others) I get the specific error:
GenericStack.h:41:16: error: dereferencing pointer to incomplete type
genStack->top->type = 0;
I have checked the other answers on stackoverflow concerning "dereferencing pointer to incomplete type" but I cant seem to understand.
You're getting an error from GenericStack, but you have a problem in both GenericStack and GenericStackNode.
In C, struct X and X are different types. When you write:
struct GenericStackNode *next;
it declares a type called struct GenericStackNode (and a member which is a pointer to that type). This type is incomplete because you have not provided the struct definition.
The type could be completed by providing a struct definition later, but you never do that. Instead, you define an unnamed struct and typedef GenericStackNode to it , but that has no effect on struct GenericStackNode.
Then, struct GenericStackNode *top; still uses this same incomplete type, not the struct you defined above.
Assuming you meant for this pointer to be a pointer to the same type of struct it's contained in, you could use this pattern for both of your structs:
typedef struct X X;
struct X
{
X *ptr;
};
Often people combine the typedef with the struct definition but I find it clearer to have them separate.
You already type-defined GenericStackNode as a type, there is no need for struct GenericStackNode anymore, just GenericStackNode :
typedef struct
{
struct GenericStackNode *top;
...
}
should be only
typedef struct
{
GenericStackNode *top;
...
}
also , you can't use GenericStackNode when you still havn't defined it yet :
typedef struct
{
struct GenericStackNode *next;
void *data;
int type;
} GenericStackNode ;
you can write :
typedef struct GenericStackNode
{
struct GenericStackNode *next;
void *data;
int type;
} GenericStackNode ;

Strings dynamic allocation in C

I'm working with C. Can you tell me if this is the right way to allocate memory for a struct which contains a string?
struct _TipoLista {
char info[10];
struct _TipoLista *next;
};
typedef struct _TipoLista *TipoLista;
...
TipoLista el;
el = malloc(sizeof(TipoLista));
If a try to create a list in this way, I always get errors when I try to insert the 2nd element while. However, if I change "info" from char[10] to an int my code always works.
el = malloc(sizeof(*el));
or
el = malloc(sizeof(struct _TipoLista));
or initializing while declaring the struct
struct _TipoLista {
char info[10];
struct _TipoLista *next;
}obj1;
In the first two cases it's dynamic memory allocation 3rd is static memory allocation
el = malloc(sizeof(*el));
TipoLista has size of a pointer so that's not what you really want.
You should try the following
el = malloc(sizeof(struct _TipoLista));
Or define a typedef for this structure.
You are trying to do a typedef i.e., an alias for the strucuture. Typedef in turn means that "from this point onwards *struct _TipoLista* will be called as *TipoLista "
If you want to have a linked list of type "struct _TipoLista", then this could help.
struct _TipoLista {
char info[10];
struct _TipoLista *next;
};
typedef struct _TipoLista TipoLista;
int main()
{
TipoLista *Tptr = malloc(sizeof(TipoLista) );
/** Rest is history */
}
Hope this can be useful:
typedef struct {
char info[10];
struct _TipoLista *next;
} TipoLista;
TipoLista* construct_lista()
{
TipoLista* ret = malloc(sizeof(TipoLista));
ret->next = NULL;
return ret;
}
void destruct_lista(TipoLista* lista)
{
TipoLista* next;
while (lista != NULL)
{
next = lista->next;
free(lista);
lista=next;
}
}
void insert_into_list(TipoLista* lista, char* element)
{
while (lista->next != NULL)
lista = lista->next;
lista->next = construct_lista();
strcpy(lista->next->info, element);
}

Resources