Struct scope problème - c

Hello I have a problem with the scope of my structure. I have a linked list struct :
typedef struct s_map
{
struct s_map *prev;
struct s_map *next;
} t_map;
typedef struct s_dblist
{
struct s_map *first;
struct s_map *last;
} t_dblist;
in my main function i create a new struct and i give my struct to the function map_loader:
int main(void)
{
t_dblist map; //create struct
map.first = NULL;
map.last = NULL;
map_loader(&map); //give adress of struct to the function map_loader
}
In map loader i call check function and give him my struct, after that i call test_parcour to check if it work
void map_loader(struct s_dblist *map)
{
check(map); //Give here my struct
test_parcour(map); //function to test the struct
}
In check function, again i just give my struct to the function setup map struct x time (loop)
static void check(struct s_dblist *map)
{
int i = 0;
while (i++ < 5) //don't care of that
setup_map_struct(map); //i give here my struct
}
And this is where everything is done, but everything is done "locally" (i think), once the function is finished, the data is deleted so when in the map_loader function I call the "test" function there are only 2 elements, the last and the first pointer, and everything that should be in between (next and prev pointer) are null.. but i don't know why, in my main function i give the adress of my struct..
static void setup_map_struct(struct s_dblist *map)
{
struct s_map *nouv = malloc(sizeof(nouv));
if(!nouv)
return ;
nouv->map_value.x = 1;
nouv->map_value.y = 2;
nouv->map_value.content = 3;
nouv->prev = (*map).last;
nouv->next = NULL;
if((*map).last)
(*map).last->next = nouv;
else
(*map).first = nouv;
(*map).last = nouv;
}
i tried this way to but my problem persist
static void setup_map_struct(struct s_dblist *map)
{
struct s_map *nouv = malloc(sizeof(nouv));
if(!nouv)
return ;
nouv->map_value.x = 1;
nouv->map_value.y = 2;
nouv->map_value.content = 3;
nouv->prev = map->last;
nouv->next = NULL;
if(map->last)
map->last->next = nouv;
else
map->first = nouv;
map->last = nouv;
}
try to make a linked list struct..

I can see that you are not allocating enough memory for your structure of type s_map (variablenouv).
static void setup_map_struct(struct s_dblist *map)
{
// Look I have modified line below vvvvvv
struct s_map *nouv = malloc(sizeof(*nouv));
// You can also use line below.
// struct s_map *nouv = malloc(sizeof(struct s_map));
if(!nouv)
return ;
nouv->map_value.x = 1;
nouv->map_value.y = 2;
nouv->map_value.content = 3;
nouv->prev = map->last;
nouv->next = NULL;
if(map->last)
map->last->next = nouv;
else
map->first = nouv;
map->last = nouv;
}
Look type of nouv is a pointer. So sizeof(nouv) will be 8 bytes. What you want is to allocate memory for type of s_map which is probably 16 bytes.

Related

Linked List not retaining values across recursive function calls?

I am trying to implement a linked list that would store a memory address when encountering call/return assembly instructions. This works recursively by parsing each line of the assembly and only breaking out of the function when encountering either a call or return instruction. So far this works for call instructions, meaning that the return address is saved a node in a linked list, but when trying to retrieve this value during a return instruction the data has gone missing (meaning that the linked list is now empty). Here is what I am working with:
struct ret_addr {
int address;
struct ret_addr *nxt;
};
struct ret_addr *ret_data(cs_insn *insn, struct ret_addr **head) {
struct ret_addr *r = malloc(sizeof(*r));
r->address = insn->address + insn->size;
r->nxt = (*head);
(*head) = r;
return r;
}
struct bb_data *disassemble_function_cfg(int startAddr, unsigned char *bytes, int end_section) {
csh handle;
cs_insn *insn;
cs_detail *detail;
cs_x86 *x86;
size_t count;
int stop_disasm = 0;
struct bb_data *edges = NULL;
struct ret_addr *ret_edge = NULL;
count = cs_disasm(handle, bytes, end_section, startAddr, 1, &insn);
detail = insn->detail;
for(int n = 0; n < detail->groups_count; n++) {
//break when encountering a call instruction
if(detail->groups[n] == X86_GRP_CALL) {
stop_disasm = 1;
vector_new(edges);
edges = call_insn(handle, x86, insn, vector_back(edges));
ret_edge = ret_data(insn, &ret_edge);
}
//break when encountering a return instruction
else if(detail->groups[n] == X86_GRP_RET) {
stop_disasm = 1;
vector_new(edges);
edges = ret_insn(insn, edges, &ret_edge);
}
}
if(!stop_disasm) {
disassemble_function_cfg(insn->address + insn->size, bytes + insn->size, end_section);
}
else {
return edges;
}
}
You don't preserve your list between recursive calls. What you might want to do:
struct bb_data *disassemble_function_cfg(struct ret_addr **ret_edge, int startAddr, unsigned char *bytes, int end_section)
{
...
if(*ret_edge == NULL) *ret_edge = ret_data(insn, ret_edge);
...
}

ds_list can't handle more than 3 elements

i don't know why i can't even add 4th element...
(im working on windows with mingw)
this is my code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 100
typedef struct ds_list_element {
char value[MAX];
struct ds_list_element *next;
}* ds_list;
int ds_list_empty(ds_list id) { // id listy
if (id == NULL) return 1;
else return 0;
}
ds_list ds_list_add(ds_list id, char add[MAX]) {
ds_list temp;
temp = (ds_list)(malloc(sizeof(ds_list)));
strcpy(temp->value,add);
temp->next = id;
return temp;
}
void ds_list_print(ds_list id) {
if (ds_list_empty(id) == 0) {
printf("%s\n",id->value);
ds_list_print(id->next);
}
}
int main () {
ds_list my_list = NULL;
my_list = ds_list_add(my_list,"one");
my_list = ds_list_add(my_list,"two");
my_list = ds_list_add(my_list,"three");
my_list = ds_list_add(my_list,"four");
ds_list_print(my_list);
return 0;
}
and the result is:
four
three
two
y
Press any key to continue . . .
i don't know why it is happening. everything should work fine.
my friend told me it is working on ubuntu...
temp = (ds_list)(malloc(sizeof(ds_list)));
will be
temp = malloc(sizeof(*temp)));
You want to allocate memory for struct ds_list_element not struct ds_list_element*. Don't hide pointers behind typedef name. It rarely helps.
Also you should check the return value of malloc and the casting is not needed.
Use ds_list as structure not a pointer
typedef struct ds_list_element {
char value[MAX];
struct ds_list_element *next;
}ds_list;
and allocate memory for the structure not a pointer.
Working program:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 100
typedef struct ds_list_element {
char value[MAX];
struct ds_list_element *next;
}ds_list;
int ds_list_empty(ds_list *id) { // id listy
if (id == NULL) return 1;
else return 0;
}
ds_list * ds_list_add(ds_list *id, char add[MAX]) {
ds_list *temp;
temp = (malloc(sizeof(ds_list)));
strcpy(temp->value,add);
temp->next = id;
return temp;
}
void ds_list_print(ds_list *id) {
if (ds_list_empty(id) == 0) {
printf("%s\n",id->value);
ds_list_print(id->next);
}
}
int main () {
ds_list *my_list = NULL;
my_list = ds_list_add(my_list,"one");
my_list = ds_list_add(my_list,"two");
my_list = ds_list_add(my_list,"three");
my_list = ds_list_add(my_list,"four");
ds_list_print(my_list);
return 0;
}
Output:
four
three
two
one

Returning a dynamically allocated array of structures from a function in C?

typedef struct {
List *table;
unsigned int size;
} HashTable;
typedef struct node {
Data data;
struct node *next;
} NODE;
struct listptrs {
NODE *tail;
NODE *head;
NODE *prev;
NODE *current;
};
typedef struct listptrs List;
HashTable createHashTable(unsigned int size) {
//HashTable htable = { 0 };
//return htable;
int i;
HashTable *htable = NULL;
htable = malloc(sizeof(HashTable) * size);
for (i = 0; i < size; i++) {
htable[i].table = malloc(sizeof(List));
htable[i].table->current = NULL;
htable[i].table->head = NULL;
htable[i].table->prev = NULL;
htable[i].table->tail = NULL;
htable[i].size = size;
}
return *htable;//???
}
Then in main:
HashTable htable = createHashTable(tableSize);
htable doesn't act like an array at all. Any ideas how to solve it without changing any return value from the function and arguments for functions? This is part of a school assignment and only the contents of the function createHashTable may be changed. The rest of the program is not here because it isn't relevant to the question.
You maybe want this:
HashTable *createHashTable(unsigned int size)
{
//HashTable htable = { 0 };
//return htable;
int i;
HashTable* htable = NULL;
htable = malloc(sizeof(HashTable)* size);
for(i=0; i<size; i++)
{
htable[i].table = malloc(sizeof(List));
htable[i].table->current = NULL;
htable[i].table->head = NULL;
htable[i].table->prev = NULL;
htable[i].table->tail = NULL;
htable[i].size = size;
}
return htable;
}
As you allocate the array dynamically, you can simply return the newly allocated pointer. Returning a HashTable as you were trying doesn't make senses, because this would allow you to return one single HashTable, but you want to return a whole array of HashTables.
Usage:
Instead of:
HashTable htable = createHashTable(tableSize);
You need this:
HashTable *htable = createHashTable(100);
...
... // when done you need to delete the hashtable
deleteHashTable(htable);
The deleteHashTable is yet to be written, It essentially needs to free the table pointer and to free the table itself.
Now if you really are allowed to change only the contents of the createHashTable function but not the function signature, then your question doesn't make sense because with the function signature HashTable createHashTable(unsigned int size) you can only return one HashTable but not an array of HashTables.
But then maybe you actually want this:
HashTable createHashTable(unsigned int size)
{
HashTable htable = { 0 };
int i;
for(i=0; i<size; i++)
{
htable[i].table = malloc(sizeof(List));
htable[i].table->current = NULL;
htable[i].table->head = NULL;
htable[i].table->prev = NULL;
htable[i].table->tail = NULL;
htable[i].size = size;
}
return htable;
}
With this second solution, you still need to write the function that deletes the hash table.
The hash table itself isn't supposed to "behave like an array", and this:
return *htable;
makes no sense, it returns the first element from your array of hash tables.
You're not supposed to create an array of hash tables though, you're supposed to create a single hash table, which might contain an array (that's the table). It also has a size variable for instance, so there's more than the array itself to the hash table.
You should do
htable = malloc(sizeof *htable);
to allocate a single instance, then initialize that as needed and return it.
There seems to be some confusion here: createHashTable() is not supposed to allocate an array of hash tables, but a HashTable structure with an initial size for its embedded table member.
Furthermore, it is non standard practice to return the structure by value. You should instead return the pointer to the allocated HashTable or possibly take a pointer to HashTable structure allocated dynamically or statically by the caller and initialize that.
Here is a modified version of the code for this approach:
#include <stdlib.h>
typedef struct {
List *table;
unsigned int size;
} HashTable;
typedef struct node {
Data data;
struct node *next;
} NODE;
struct listptrs {
NODE *tail;
NODE *head;
NODE *prev;
NODE *current;
};
typedef struct listptrs List;
HashTable *createHashTable(unsigned int size) {
HashTable *htable = malloc(sizeof(*htable));
if (htable == NULL)
return NULL;
}
htable->size = size;
htable->table = NULL;
if (size == 0) {
return htable;
}
htable->table = malloc(sizeof(*htable->table) * size);
if (htable->table == NULL) {
free(htable);
return NULL;
}
for (unsigned int i = 0; i < size; i++) {
htable->table[i].head = NULL;
htable->table[i].tail = NULL;
htable->table[i].prev = NULL;
htable->table[i].current = NULL;
}
return htable;
}
Calling from main():
HashTable *htable = createHashTable(100);

initialization of flexible array of struct pointers in a struct in c

I'm learning hashtable data structures and I want to make a hashtable with a flexible length array of pointers to struct Link (linked list pieces), so that hashtable initialization will set the array to be a length input into the initialization function.
At first I was getting the error "flexible array not at the end of struct". When its at the end (as shown) the program crashes (but it still compiles). This is my code:
typedef struct Link{
int key;
char *name;
struct Link *next;
} Link;
typedef struct HashTable{
int numberOfEntries;
int numberOfBuckets;
Link *Table[];
} HashTable;
HashTable *hashtableInit(int size){
HashTable *newHT = malloc(sizeof(HashTable));
if (newHT != NULL){
newHT->numberOfEntries = 0;
newHT->numberOfBuckets = size;
for (int i = 0; i < newHT->numberOfBuckets; i += 1){
newHT->Table[i] = NULL;
}
return newHT;
} else {
printf("Error in memory allocation.\n");
fflush(stdout);
return NULL;
}
}
}
It works if I set the array to a constant and input the same value into the init function:
#define SIZE 11
typedef struct Link{
int key;
char *name;
struct Link *next;
} Link;
typedef struct HashTable{
Link *Table[SIZE];
int numberOfEntries;
int numberOfBuckets;
} HashTable;
HashTable *hashtableInit(int size){ // works if SIZE is passed into function as size parameter
HashTable *newHT = malloc(sizeof(HashTable));
if (newHT != NULL){
newHT->numberOfEntries = 0;
newHT->numberOfBuckets = size;
for (int i = 0; i < newHT->numberOfBuckets; i += 1){
newHT->Table[i] = NULL;
}
return newHT;
} else {
printf("Error in memory allocation.\n");
fflush(stdout);
return NULL;
}
}
}
The second code block works perfectly. Any insights would be greatly appreciated. Thanks for your time.
Chris
You should allocate memory as
HashTable *newHT = malloc(sizeof *newHT + size * sizeof newHT->Table[0]);
Your
HashTable *newHT = malloc(sizeof(HashTable));
is wrong, because no space is given for the flexible array member. Should probably be
HashTable *newHT = malloc(sizeof(HashTable)+size*sizeof(Link*));

Passing struct to function and adding elements

I'm new to C. I'm trying to pass a struct list to a function and within that function fill the list. Code is as follows:
#include <stdio.h>
#include <stdlib.h>
struct Abc {
int test;
struct Abc *next;
};
void demo_fill(struct Abc *data);
int main(int argc, char **argv) {
struct Abc *db = NULL;
demo_fill(db);
printf("%d\n",db->test);
return 0;
}
void demo_fill(struct Abc *data) {
int i;
for( i = 0; i < 5; i++ ) {
struct Abc *new;
new = malloc(sizeof(struct Abc));
new->test = i;
new->next = data;
data = new;
}
}
When running this a 'Segmentation fault (core dumped)' error occurs because the struct is still NULL when I try to print the first element. What am I doing wrong?
You're passing the pointer by value. You need to pass a pointer to a pointer if you want the change the value of the caller's pointer:
int main(int argc, char **argv) {
struct Abc *db = NULL;
demo_fill(&db);
printf("%d\n",db->test);
return 0;
}
void demo_fill(struct Abc **data) {
int i;
for( i = 0; i < 5; i++ ) {
struct Abc *new;
new = malloc(sizeof(struct Abc));
new->test = i;
new->next = *data;
*data = new;
}
}
Assigning data to new will have no effect. data is a local copy of the pointer. Pass a double pointer to fix that. Something like this:
void demo_fill(struct Abc** data) {
int i;
for( i = 0; i < 5; i++ ) {
struct Abc *new;
new = malloc(sizeof(struct Abc));
new->test = i;
new->next = *data;
*data = new;
}
}
And of course you will have to pas the pointer to db in main:
demo_fill(&db)
You can pass a pointer to the pointer as the other two answers say, so i just point out an alternative you might also consider: Instead of using a single struct you could use one struct for the list and another for entry-links:
struct link {
int test;
struct link* next;
};
struct list {
struct link* first;
};
void demo_fill(struct list* data);
You can then modify the first entry of the list without thinking about ** syntax.

Resources