realloc array of struct inside another struct - c

I'm working on a project where the goal is to create automatons.
Automatons are defined by a struct :
typedef struct {
int num_states;
int initial_state;
State * states;
} Automaton;
And State is another struct defining arcs between states:
typedef struct {
int num_arcs;
bool is_final;
Arc * arcs;
} State;
typedef struct {
int symbol;
int destination;
} Arc;
I create an automaton with malloc as such :
Automaton* create_automaton(void) {
Automaton * a = (Automaton *)malloc(sizeof(Automaton));
assert(a != NULL);
a->initial_state = UNDEFINED;
a->num_states = 0;
a->states = NULL;
return a;
}
So then I want to take 2 Automatons with states and arcs created with these functions :
int add_state(Automaton* a) {
State* state = (State *)realloc(a->states, (a->num_states + 1) * sizeof(State));
if(state == NULL)
exit(EXIT_FAILURE);
a->states = state;
a->states[a->num_states].num_arcs = 0;
a->states[a->num_states].is_final = FALSE;
a->states[a->num_states].arcs = NULL;
return a->num_states++;
}
void add_arc(Automaton* a, int from, int to, int symbol) {
if(from >= a->num_states || to >= a->num_states)
exit(EXIT_FAILURE);
Arc * arc = (Arc *)realloc(a->states[from].arcs, (a->states[from].num_arcs + 1) * sizeof(Arc));
if(arc == NULL)
exit(EXIT_FAILURE);
a->states[from].arcs = arc;
a->states[from].arcs[a->states[from].num_arcs].destination = to;
a->states[from].arcs[a->states[from].num_arcs].symbol = symbol;
a->states[from].num_arcs++;
}
I want to combine these 2 Automatons in one so I wrote this function:
Automaton* append_automaton(Automaton * a1, Automaton * a2)
{
Automaton * a = copy_automaton(a1);
int i = 0;
for(i = 0; i < a2->num_states; i++)
{
add_state(a);
a->states[a1->num_states + i] = a2->states[i];
for(j = 0;j<a->states->num_arcs;j++)
{
a->states[i].arcs[j].destination =+ a2->num_states;
}
}
a->initial_state = a1->initial_state;
return a;
}
However I can create the Automaton, add states and arcs to it without any problem, when i try to merge them together with append_automaton I get a segmentation fault when in add_state() I realloc State to fit one more state in the new automaton.
So my question is the following : Why is realloc giving me a segmentation fault when in this function (append_automaton) althought it works perfectly outside of it?
PS: copy_Automaton() does indeed overwrite the create_Automaton() so I removed the line: Automaton * a = create_automaton() in append_automaton()
And here is copy_automaton():
Automaton* copy_automaton(Automaton* a) {
int i = 0;
Automaton * cp_a = malloc(sizeof(Automaton));
cp_a->states = malloc(sizeof(a->states));
for(i = 0; i < a->num_states; i++)
{
cp_a->states[i].arcs = malloc(sizeof(a->states[i].arcs));
cp_a->states[i] = a->states[i];
}
cp_a->num_states = a->num_states;
cp_a->initial_state = a->num_states;
//memcpy(a, cp_a, sizeof(Automaton));
return cp_a;
}

The problem I see is your are updating a->num_states after the for cycle. However a->num_states it is used inside the cycle in the function add_state(a);
You need to put (a->num_states)++ inside the loop.

Related

Creating struct objects and puttin them into an array

I'm trying to solve a problem I'm having with a function that will create a new struct objects and then put it in an dynamic array. I have tried multiple variations but i keep running into various problems. This is what I'm working with right now, but I'm getting a memory access problem.
typedef struct {
int keynr;
int access;
time_t lastused;
} keycard;
void keyCreate(keycard *cardList, int keyid) {
cardList[keyid].keynr = keyid + 100;
cardList[keyid].access = 1;
cardList[keyid].lastused = 0.0;
}
int main () {
keycard *cardList = 0;
cardList = malloc(sizeof(keycard) * 1);
keyCreate(&cardList, 0);
printf("%d", cardList[0].access);
This code gives me: Exception thrown: read access violation.
cardList was 0x64.
I've been reading alot about pointers and memmory allocation but obviously i am missing something..
You if you want to duynamically add new cards to the array, you need to wrap it in another data structure:
typedef struct
{
int keynr;
int access;
time_t lastused;
} keycard;
typedef struct
{
keycard *keyarray;
size_t size;
}keystorage;
int keyCreate(keystorage *cardList, size_t keyid)
{
if (cardList -> keyarray == NULL || keyid + 1 > cardList -> size)
{
keycard *new = realloc(cardList -> keyarray, sizeof(*(cardList -> keyarray)) * (keyid + 1));
if(!new) return -1; //error
cardList -> keyarray = new;
cardList -> size = keyid + 1;
}
cardList -> keyarray[keyid].keynr = keyid + 100;
cardList -> keyarray[keyid].access = 1;
cardList -> keyarray[keyid].lastused = 0.0;
return 0; //OK
}
int main (void) {
keycard key;
keystorage cards = {NULL, 0};
keyCreate(&cards, 500);
printf("%d", cards.keyarray[500].access);
return 0;
}
You are passing the incorrect type to keyCreate. This function expects a pointer to keycard, but you are passing it a double pointer instead. The & means "take the address of", which turns cardList into a keyCard** type. Instead, consider the following:
void keyCreate(keycard *cardList, int keyid) {
cardList[keyid].keynr = keyid + 100;
cardList[keyid].access = 1;
cardList[keyid].lastused = 0; // time_t is most likely a signed integer
}
int main (void) {
keycard *cardList = malloc(sizeof(keycard) * 1);
// always check if malloc succeeds, and if it does not, handle the error somehow
if (cardList == NULL)
{
fprintf(stderr, "Insufficient mem\n");
return -1;
}
keyCreate(cardList, 0);
printf("%d\n", cardList[0].access); // the \n will flush the output and
// put each item on its own line
// cleanup when you're done, but the OS will do this for you when the
// process exits also
free(keyCreate);
return 0;
}
Also, time_t is most likely a signed integer (What is ultimately a time_t typedef to?), so assigning it to 0.0 is probably not right, but you'll need to check what it typedefs to on your system.
Finally, I assume this is just an MCVE, but I'd advise against mallocing in this case. The 2 primary reasons to malloc are when you don't know how much data you'll need until runtime, or you need "a lot" of data. Neither of those are true in this case. Just from what you've presented, I'd probably do the following:
#define NUM_KEY_CARDS 1
void keyCreate(keycard *cardList, int keyid) {
cardList[keyid].keynr = keyid + 100;
cardList[keyid].access = 1;
cardList[keyid].lastused = 0; // time_t is most likely a signed integer
}
int main (void) {
keycard cardList[NUM_KEY_CARDS];
for (int keyid=0; keyid<NUM_KEY_CARDS; keyid++)
{
keyCreate(cardList+keyid, keyid);
// or keyCreate(&(cardList[keyid]), keyid);
printf("%d\n", cardList[keyid].access);
}
return 0;
}

Can't access pointer while navigating linked list

I'm making a simple hash table and a hash function. Each element of the table has a pointer to another node that is used by the insert function when a collision occurs. The problem is that when a collision occurs my code simply crashes when it's navigating the linked list. Here is the code (sorry if it's a little lengthy):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hash.h"
#define TAM 50
int funcaoHash(int chave, char nome[50]) //Hash function
{
int i;
int hash = chave;
for(i = 0; nome[i] != '\0'; i++)
{
hash = hash + (int)nome[i];
}
hash = hash%TAM;
return hash;
}
void insere(int chave, char nome[50], itemTabela* TabelaHash[TAM]) //Insert function
{
int idx = funcaoHash(chave, nome);
itemTabela* ItemAux = (itemTabela*)malloc(sizeof(itemTabela));
itemTabela* ptrAux = NULL;
ItemAux->chave = chave;
strcpy(ItemAux->nome, nome);
if(TabelaHash[idx] == NULL) //No collision occurred
TabelaHash[idx] = ItemAux;
//If there is a collision
else
{
ptrAux = TabelaHash[idx]->ptr;
//Here the code breaks
while(ptrAux->ptr != NULL)
{
ptrAux = ptrAux->ptr;
}
ptrAux = ItemAux;
}
}
void inicializaTabela(itemTabela* TabelaHash[TAM]) //Initialize tabl
{
int i;
for(i = 0; i < TAM; i++)
TabelaHash[i] = NULL;
}
Here is the node structure:
typedef struct itemTabela
{
char nome[50];
int chave;
struct itemTabela* ptr;
}itemTabela;
And here is the main function:
int main()
{
itemTabela *ptrTabela[TAM] = {};
inicializaTabela(ptrTabela);
insere(6, "Chico", ptrTabela);
insere(6, "Chico", ptrTabela);
return 0;
}
Am I accessing the pointers in the wrong way or doing some ilegal access?
Thanks for your time!
1)
Initialization of ItemAux also requires ptr initialization. like ItemAux->ptr = NULL;
2)
ptrAux = TabelaHash[idx]->ptr;
//Here the code breaks
while(ptrAux->ptr != NULL)
{
ptrAux = ptrAux->ptr;
}
ptrAux = ItemAux;
should be
ptrAux = TabelaHash[idx];
while(ptrAux->ptr != NULL)
{
ptrAux = ptrAux->ptr;
}
ptrAux->ptr = ItemAux;

Cannot retrieve all the data from Hashtable

I am trying to code an algorithm in C that reads a huge file ( more than 750.000 lines) , separates each line by some specified delimiters , and saves the data into a structure , which is then saved into a Hashtable. Everything goes fine until I want to print one specific data for each row of the Hashtable: the output is good for some rows , but the console is just printing some random symbols for others (which means memory leaks maybe? ).
I am trying to figure what can cause this problem. If I isolate the code that separate the line and saves it into the structure, and execute it for each line separately, it works fine, everything is printed as expected.
I have also tried to do it without dynamic allocation but it works a bit better with it as I was getting the infamous "Segmentation fault"
Here is the code that splits the line and saves it:
unsigned int hash(unsigned int id) {
unsigned int hashage = 5381; //Valeur arbitraire
unsigned int mdop = 10; //faire un modulo obtenir l'unite
int idtmp = id;
while (mdop < id) {
idtmp = id%mdop;
hashage = ((hashage << 6) + hashage) + idtmp;
mdop *= 10;
}
return hashage % NB_CASES_HASH;
}
void initiate_hashtable(Hashtable hashtable) {
int i = 0;
for (; i < NB_CASES_HASH; i++) {
hashtable[i] = NULL;
}
}
void ajout_entete(Liste *liste, Oeuvre *oeuvre) {
Liste p = malloc(sizeof(Cellule));
if (!p) exit(EXIT_FAILURE);
p->oeuvre = *oeuvre;
p->suiv = *liste;
//Si on imprime ici , tout va bien , les données sont correctes
*liste = p;
}
void ajout_annee(Liste *liste, Oeuvre *oeuvre) { //ajout trié par année pour recherche plus rapide
if (!(*liste) || oeuvre->year <= (*liste)->oeuvre.year)
ajout_entete(liste,oeuvre);
else {
if (oeuvre->year >= (*liste)->oeuvre.year)
ajout_annee(&(*liste)->suiv, &oeuvre);
}
}
Oeuvre peuple_oeuvre(char line[MAX_CHARS_LINE]) {
int i = 0, j = 1, cmpt = 0;
char strings[CHAMPS_OEUVRE][MAX_SIZE];
char carac = *(line);
char mot[MAX_SIZE];
mot[0] = carac;
bool isSuivi = false;
Oeuvre oeuvre;
while (carac != '\n') {
if (carac == ',') {
if(isSuivi) {
mot[j - 1] = '\"';
mot[j] = '\0';
isSuivi = false;
} else
mot[j - 1] = '\0';
strcpy(strings[i], mot);
j = 0;
i++;
} else
if (carac == '\"') {
cmpt++;
carac = *(line + cmpt);
while (carac != '\"') {
mot[j] = carac;
j++;
cmpt++;
carac = *(line + cmpt);
}
isSuivi = true;
}
cmpt++;
carac = *(line + cmpt);
mot[j] = carac;
j++;
}
mot[j] = '\0';
strcpy(strings[i], mot);
//Assignation des valeurs :
oeuvre.id = atoi(strings[0]);
oeuvre.accession_number = strdup(strings[1]);
oeuvre.artiste.nomArtiste = strdup(strings[2]);
oeuvre.artiste.artistRole = strdup(strings[3]);
oeuvre.artiste.artistId = atoi(strings[4]);
oeuvre.titre = strdup(strings[5]);
oeuvre.url = strdup(strings[CHAMPS_OEUVRE]);
oeuvre.year = atoi(strings[9]);
return oeuvre;
}
void peuple_hashtable(Hashtable hashtable) { // Peuplement par redirection
char ligne[MAX_CHARS_LINE];
fgets(ligne, MAX_CHARS_LINE, stdin);
Oeuvre *oeuvre = malloc(sizeof(Oeuvre));
int hashNum;
while (fgets(ligne, MAX_CHARS_LINE, stdin)) {
*oeuvre = peuple_oeuvre(ligne);
hashNum = hash(oeuvre->artiste.artistId);
ajout_annee(&hashtable[hashNum], oeuvre);
}
}
int main() {
Hashtable hashtable;
initiate_hashtable(hashtable);
peuple_hashtable(hashtable);
return 0;
}
And the Oeuvre structure looks like this :
typedef struct oeuvre {
unsigned int id;
char *accession_number;
Artiste artiste;
char *titre;
int year;
char *url;
} Oeuvre;
typedef Liste Hashtable[NB_CASES_HASH];
Thanks in advance.
There are many problems in your code.
If line does not contain a newline or if a double quote is missing, the behavior is undefined.
You do not initialize the string array: if the description has missing fields, the behavior is undefined.
In the part where you save the structure fields, your allocation code is incorrect: you must allocate one more character than the length of the string, strlen(string[0]) + 1 instead of strlen(string[0]) * sizeof(char*).
It would be much simpler to use the POSIX function strdup():
// Assigning the values:
oeuvre.id = atoi(strings[0]);
oeuvre.accession_number = strdup(strings[1]);
oeuvre.artiste.nomArtiste = strdup(strings[2]);
oeuvre.artiste.artistRole = strdup(strings[3]);
oeuvre.artiste.artistId = atoi(strings[4]);
oeuvre.titre = strdup(strings[5]);
oeuvre.url = strdup(strings[CHAMPS_OEUVRE]));
oeuvre.year = atoi(strings[9]);
Solved my issue by declaring the Oeuvre structure like this
typedef struct oeuvre {
unsigned int id;
char accession_number[MAX_CHARS];
Artiste artiste;
char titre[MAX_CHARS];
int year;
char url[MAX_CHARS];
} Oeuvre;
with MAX_CHARS referring to a large number.
So I believe I was not properly allocating the strings before using them, which made them to point to random adresses , resulting in those weird outputs but no error. I also believe that another way of solving this would be to dynamically allocate the chars for each Oeuvre in my function.

Uninitialised value was created by a heap allocation for allocation of an array of struct

Valgrind is complaining about a method and I really cannot figure out why. The error message I get is following:
==1664== Uninitialised value was created by a heap allocation
==1664== at 0x47F1: malloc (vg_replace_malloc.c:302)
==1664== by 0x100004B6A: filter_my_struct_list (main.c:3357)
==1664== by 0x100002C7C: main (main.c:370)
In the method he complains about I am just trying to "compress" a list, meaning, I am merging consecutive elements of my structure to one.
my_struct is just a structure with two int values:
typedef struct {
int start;
int len;
} my_struct;
And the method looks like:
my_struct* filter_my_struct_list(my_struct *listl, int *elements_in_list) {
my_struct *compressed_list;
if (*elements_in_list == 0) {
fprintf(stderr, "Number of my_structs should not be zero! Please check the input!\n");
exit(1);
} else if (*elements_in_list == 1) {
compressed_list = malloc(sizeof(my_struct)* 1);
my_struct f = {listl[0].start, listl[0].len};
compressed_list[0] = f;
return compressed_list;
}
int fst, remained_index;
remained_index = fst = 0;
compressed_list = malloc(sizeof(my_struct) * (*elements_in_list)); //<== The line valgrind doesn't like
while (fst < (*elements_in_list - 1)) {
int fst_in_loop = fst;
int nxt = fst_in_loop + 1;
BOOL terminate = FALSE;
while (!terminate) {
if (((listl[fst_in_loop].start + listl[fst_in_loop].len) == listl[nxt].start)) {
fst_in_loop++;
nxt++;
} else terminate = TRUE;
if (nxt == (*elements_in_list)) {
terminate = TRUE;
}
}
if (fst_in_loop != fst) {
int new_len = listl[fst_in_loop].start
+ listl[fst_in_loop].len - listl[fst].start;
my_struct f = {listl[fst].start, new_len};
compressed_list[remained_index] = f;
} else {
my_struct f = {listl[fst].start, listl[fst].len};
compressed_list[remained_index] = f;
}
remained_index++;
fst = nxt;
if (nxt == (*elements_in_list - 1)) {
if (fst == fst_in_loop) {
int f_1;
for (f_1 = fst; f_1 <= nxt; f_1++) {
my_struct f = {listl[f_1].start, listl[f_1].len};
compressed_list[remained_index] = f;
remained_index++;
}
} else {
my_struct f = {listl[nxt].start, listl[nxt].len};
compressed_list[remained_index] = f;
remained_index++;
}
}
}
*elements_in_list = remained_index;
return compressed_list;
}
Why is he telling me it is not initialised since I am catching the cases when there are less than two elements to be merged??
EDIT:
Ok i just found out, when I call only this method, the error disappears, but as soon as I reuse my list, the error appears

Array structure not working correctly

I have an array which has a key and info for each index in the array.
This builds the array
table_t *table_construct (int table_size, int probe_type)
{
int i;
table_t *hash;
if(table_size < 1) return NULL;
hash = malloc(sizeof(table_t));
hash->table = malloc(sizeof(list_t*) * table_size);
for(i=0; i < table_size - 1; i++)
{
hash->table[i] = NULL;
//hash->table[i]->next = NULL;
}
hash->size = table_size;
hash->probing_type = probe_type;
return hash;
}
So I have the list_t and the table_t structures. I have the following line in my code that is not working correctly:
hash->table[item]->K = K;
It can be seen in this part of my code:
int dec, item, hold;
item = hashing(hash,K);
hold = item;
if(hash->table[item] == NULL)
{
hash->table[item]->K = K;
hash->table[item]->I = I;
return 0;
}
When I GDB it, K is a number.
So what is happening here is, I have my table which is indexed with item. Then I add K to the key of the index. When ever this line comes up anywhere in my program I get a seg Fault.
Can you see anything Ive done wrong here?
You verified your pointer is null, so before you can reference off it you need to assign it something:
if(hash->table[item] == NULL)
{
hash->table[item] = malloc(sizeof(list_t)); // you were missing this.
hash->table[item]->K = K;
hash->table[item]->I = I;
return 0;
}
According to what you posted in your table_construct function, the elements of table array are null pointers. You are not allowed to perform any kind of access through null pointers.
And this just doesn't make sense
if(hash->table[item] == NULL)
{
hash->table[item]->K = K;
hash->table[item]->I = I;
return 0;
}
Here you make an explicit attempt to write data through a null pointer.
You have to make sure a pointer points to a valid object before you make any attempts to access anything (write or read) through that pointer.
In your function table_construct,when you malloc hash->table,you should do it like this.
hash->table = (list_t **)malloc(sizeof(list_t*) * table_size);
for (i=0;i<table_size;i++)
{
hash->table[i] = (list_t *)malloc(sizeof(list_t));
}
You do that made then null,if you want to do like this.
memset(hash->table[i],0,sizeof(list_t));
Then you can use this judgment statement.
if(hash->table[item] != NULL)
{
hash->table[item]->K = K;
hash->table[item]->I = I;
return 0;
}

Resources