Realloc in C for structs containing dynamic array of structs - c

Issues with reallocing the items list. I am trying to add items into the testList structs items, but i am getting memory address errors when trying to add or print the values for the individual ListItems. Any help would be greatly appreciated.
struct ListItems
{
int id;
int name;
};
struct testList
{
struct ListItems** items;
int count;
int size;
};
struct Test
{
struct testList* list;
};
void printArray(struct testList* list)
{
for (int i = 0; i < list->count; i++)
{
printf("id=%i, name= %i \n", list->items[i]->id, list->items[i]->name);
fflush(stdout);
}
printf("printing accomplished \n");
fflush(stdout);
}
void growArray(struct testList* list, struct ListItems* item)
{
int size = list->size;
list->items[list->count++] = item;
struct ListItems** user_array = list->items;
//printf("array count %i, array size %i \n", list->count, size);
if (list->size == list->count)
{
struct ListItems* temp = realloc(*user_array, (size * 2) * sizeof (struct ListItems));
if (temp == NULL)
{
printf("it's all falling apart! \n");
}
else
{
*user_array = temp;
list->size = size * 2;
}
}
}
/*
*
*/
int main(int argc, char** argv)
{
struct Test* test = (struct Test*) malloc(sizeof (struct Test));
test->list = (struct testList*) malloc(sizeof (struct testList));
test->list->count = 0;
test->list->size = 1;
test->list->items = (struct ListItems**) malloc(sizeof (struct ListItems*));
for (int i = 0; i < 32; i++)
{
struct ListItems* item = (struct ListItems*) malloc(sizeof (struct ListItems));
item->id = i;
item->name = i;
growArray(test->list, item);
}
printArray(test->list);
for (int j = 0; j < sizeof (test->list->items); j++)
{
free(test->list->items[j]);
}
free(test->list->items);
free(test->list);
free(test);
}

The problem starts with the declaration of struct testList. A pointer to an array of items should have just one *:
struct testList
{
struct ListItems* items; // Changed from pointer-to-pointer
int count;
int size;
};
This will force some other changes in the code.

Your growArray() needs to update list->items. In current code, it will point forever to an 1-element sized area only.
EDIT:
your realloc() allocates for sizeof (struct ListItems)) but pointer holds pointers, not elements.
I would write:
void growArray(struct testList* list, struct ListItems* item)
{
if (list->size <= list->count) {
size_t new_size = 2 * list->size;
struct ListItems** temp = realloc(list->items, new_size * sizeof temp[0]);
assert(temp);
list->size = new_size;
list->items = temp;
}
list->items[list->count] = item;
++list->count;
}
With this, you do not need the initial list->items = malloc(...) in main() but can assign NULL.
EDIT:
for (int j = 0; j < sizeof (test->list->items); j++)
does not make sense; you probably want to j < test->list->count.

Related

c deleting element in dynamic struct

i'm trying to delete a single element in the struct and override this position with the last one.
Here is my code of a function:
int deleteElement(struct record **rec, int *length, int elementToDelete){
struct record *temp = NULL;
allocateTempMemory(&temp, ((*length) - 1));
for (int i = 0; i < ((*length) - 1); i++){
if (elementToDelete != i){
temp[i] = (*rec)[i];
temp[i].ID = (*rec)[i].ID;
temp[i].Salary = (*rec)[i].Salary;
strcpy(temp[i].Name, (*rec)[i].Name);
} else {temp[i] = (*rec)[(*length) - 1];
temp[i].ID = (*rec)[(*length) - 1].ID;
temp[i].Salary = (*rec)[(*length) - 1].Salary;
strcpy(temp[i].Name, (*rec)[(*length) - 1].Name);
};
}
free(*rec);
*rec = temp;
for (int i = 0; i < ((*length) - 1); i++){
(*rec)[i] = temp[i];
(*rec)[i].ID = temp[i].ID;
(*rec)[i].Salary = temp[i].Salary;
strcpy((*rec)[i].Name, temp[i].Name);
}
(*length)--;
free(temp);
return 1;
}
code of the struct
struct record{
char Name[100];
double Salary;
int ID;
};
code of the function allocateTempMemory:
int allocateTempMemory(struct record **temp, int length){
*temp = (struct record **)malloc(sizeof(struct record) * length);
if (temp == NULL){
return 0;
}
return 1;
}
However, it does not work properly. My guess are memory allocation issues (sometimes it runs through and sometimes it crashes immediately). Do you have any idea what the problem may be? thanks
You assign temp to *rect, than you free temp. basically you freed *rec. When you access *rec later it will cause crash.
*rec = temp;
....
free(temp); // cause *rec freed. Should not be freed.

Understanding how to convert void* and int* in C

I have written the following code:
typedef struct List {
struct List* next;
void *value;
} List;
void freeList(List* list, void destroyElement(void*)) {
while(list != NULL) {
destroyElement(list->value);
struct List* n = list;
list = list->next;
free(n);
}
}
struct List* arr2list(void** array, int length, void* cpyElement(void*), void (*destroyElement)(void*)) {
struct List* head = NULL;
struct List** tail = &head;
for(int i = 0; i < length; i++) {
*tail = calloc(1, sizeof(struct List));
printf("array[%d] = %d\n",i,*(((int*)array)+i));
if (*tail == NULL) {
freeList(head, destroyElement);
return NULL;
}
tail[0]->value = cpyElement(array[i]);
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
}
void printList(List* list, void echoElement(void*)) {
while (list != NULL) {
echoElement(list->value);
list = list->next;
}
}
void destroyElement(void* el) {
if (el != NULL) {
struct List* node = el;
node->next = NULL;
free(node);
}
}
void* cpyElement(void* el) {
int *p = malloc(sizeof(*p));
*p = *(int *) el;
return p;
}
void echoElement(void* el) {
if (el != NULL) {
printf("%d ", *(int *) el);
}
}
int main(int argc, char** argv) {
int array_length = argc - 1;
int* array = (int*) malloc(sizeof(*array) * array_length);
for (int i = 0; i < array_length; i++){
*(array + i) = atoi(argv[i + 1]);
}
struct List* root = arr2list((void*) array,array_length,cpyElement, destroyElement);
printList(root,echoElement);
freeList(root,destroyElement);
free(array);
return 0;
}
The problem is with tail[0]->value = cpyElement(array[i]);. I get a segmentation fault error for this part. If I write it cpyElement(((int*)array)+i); it works but I want the function arr2list to be generic and not to mention int. How can I solve it? I think that I understand it's impossible to convert void* to int* because it does not know which size to use so is it possible to hear some suggestions on how to approach this issue so it will work? Maybe change the array argument?
You need to create an array of pointers to ints and then pass that. Yes, it's a lot of malloc calls, but it's necessary (since you're using void *).
int main(int argc, char** argv) {
struct List *root;
int i, array_length = argc - 1;
int** array = malloc(sizeof(*array) * array_length);
for (i = 0; i < array_length; i++){
array[i] = malloc(sizeof(*array[i]));
*array[i] = atoi(argv[i + 1]);
}
root = arr2list((void **)array,array_length,cpyElement, destroyElement);
printList(root,echoElement);
freeList(root,destroyElement);
free(array);
return 0;
}
This code:
void destroyElement(void* el) {
if (el != NULL) {
struct List* node = el;
node->next = NULL;
free(node);
}
}
will then need to be changed to (in fact, it only worked before due to a platform-specific bug):
void destroyElement(void* el) {
free(el);
}
Also, do not cast the result of malloc. That means no (int *)malloc(...). Just use malloc(...), it's safer and doesn't cover up errors.
The problem with void * is that while you can freely convert other pointer types to void * and back again and get the original pointer back, you need to do that directly -- you can't pass a void ** where it points at anything other than void *'s and expect it to work.
Even worse, in your case, you're passing an array of int where an array of void * are expected. You can deal with this by casting yout ints to intptr_t and thence to void * to store in your list -- you'll have to do that double-cast back again to get them out again:
void echoElement(void* el) {
printf("%d ", (int)(intptr_t)el);
}
int main(int argc, char** argv) {
int array_length = argc - 1;
void *array = malloc(sizeof(*array) * array_length);
for (int i = 0; i < array_length; i++) {
array[i] = (void *)(intptr_t)atoi(argv[i + 1]);
}
struct List* root = arr2list((void*) array,array_length,cpyElement, destroyElement);
printList(root,echoElement);

Hash table init_hash in c

I need to initialized the hash table with the size i get, i have a problem here t->arr_table[i]->key = NULL;
#include <stdio.h>
typedef struct element{
char * key;
char * value;
}element;
typedef struct HashTable{
int size; // size of the arr
element **arr_table; //arr of elements
}HashTable;
void init_hash(int size, HashTable * t)
{
if (size < 1)
return;
t->size = size;
t->arr_table = (element **)malloc(sizeof(element*)*size);
if (t->arr_table == NULL) // out memory
return;
int i;
for (i = 0; i < size; i++)
{ // initial list
t->arr_table[i]->key = NULL;
t->arr_table[i]->value = NULL;
}
}
void main()
{
HashTable *ht = (HashTable*)malloc(1*sizeof(HashTable));
int size_ht = 9;
init_hash(size_ht, ht);
printf("...\n");
return;
}
What you've made is an array of pointers to elements. However, the init_hash function seems to expect an array of elements. To create an array of elements the code should be as shown below. I've added some comments to highlight some of the changes.
typedef struct element{
char *key;
char *value;
}element;
typedef struct HashTable{
int size;
element *arr_table; // <-- only one '*', not two, to declare a pointer to an array of elements
}HashTable;
void init_hash(int size, HashTable *t)
{
if (size < 1)
return;
t->size = size;
t->arr_table = malloc(sizeof(element) * size); // <-- allocate memory for the elements, note 'sizeof(element)' not 'sizeof(element *)'
if (t->arr_table == NULL)
return;
int i;
for (i = 0; i < size; i++)
{
t->arr_table[i].key = NULL; // <-- table[i] is a structure, use dot notation
t->arr_table[i].value = NULL;
}
}
int main( void ) // <-- declare main with the correct signature
{
HashTable *ht = malloc(sizeof(HashTable)); // <-- don't cast the return value from malloc
int size_ht = 9;
init_hash(size_ht, ht);
printf("...\n");
}

How to find out what causes memory leak while freeing tree in C

I'm trying to find out which part of my code causes memory leaks.
To be more specific I already presume where it all begins but have no idea what to do to fix it.
These are my structures:
typedef struct {
char *suffix;
int occurr;
} suff_t;
typedef struct {
char **prefix;
suff_t **suffix;
int n_suff;
int cap_suff;
} data_t;
typedef struct node {
data_t *d;
struct node *left, *right;
} node_t, *tree_t;
And functions where I use malloc / realloc :
tree_t insert( tree_t t, char **buf, int ngram ) {
if( t == NULL ) {
node_t *n = malloc( sizeof *n);
n->d = create_data(buf, ngram);
n->left = n->right = NULL;
return n;
} else if( cmp_data( t->d, buf, ngram ) > 0 ) {
t->left = insert( t->left, buf, ngram);
return t;
} else if( cmp_data( t->d, buf, ngram ) < 0 ) {
t->right = insert( t->right, buf, ngram);
return t;
} else { // add suffix
insert_suffix(t->d, buf, ngram);
return t;
}
}
void insert_suffix(data_t *data, char **buf, int ngram) {
int i;
int cap;
for(i = 0; i < data->n_suff; i++) {
if( ! (strcmp(buf[ngram-1], data->suffix[i]->suffix)) ) {
data->suffix[i]->occurr++;
return;
}
}
if(data->n_suff == data->cap_suff){ // extend table of suffixes
cap = data->cap_suff;
data->suffix = realloc(data->suffix, 2*cap*sizeof*data->suffix); //
for(i = cap; i < 2*cap; i++)
data->suffix[i] = malloc(sizeof(suff_t));
data->cap_suff *= 2;
}
data->suffix[data->n_suff]->suffix = strdup(buf[ngram-1]);
data->suffix[data->n_suff]->occurr = 1;
data->n_suff++;
}
data_t * create_data(char **buf, int ngram) {
int i;
data_t *newdata = malloc(sizeof*newdata); //
newdata->prefix = malloc((ngram-1)*sizeof*newdata->prefix);
for(i = 0; i < ngram-1; i++) // copy prefix
newdata->prefix[i] = strdup(buf[i]);
newdata->suffix = malloc(8*sizeof*newdata->suffix);
for(i = 0; i < 8; i++)
//newdata->suffix[i] = malloc(sizeof*newdata->suffix[i]);
newdata->suffix[i] = calloc(sizeof*newdata->suffix[i], 1);
newdata->suffix[0]->suffix = strdup(buf[ngram-1]);
newdata->suffix[0]->occurr = 1;
newdata->n_suff = 1;
newdata->cap_suff = 8;
return newdata;
}
void free_data(data_t *d, int ngram) {
int i;
if(d == NULL) return;
printf("deleting data\n");
for(i = 0; i < ngram-1; i++)
free(d->prefix[i]);
free(d->prefix);
for(i = 0; i < d->cap_suff; i++) {
free(d->suffix[i]->suffix);
free(d->suffix[i]);
}
free(d->suffix);
free(d);
}
void free_tree(tree_t t, int ngram) {
if( t == NULL) return;
free_data(t->d, ngram);
free(t->left);
free(t->right);
printf("DELETING NODE\n");
free(t);
}
Valgrind prompts that something is wrong with function create_data and insert .
Please help
Valgrind is pointing to the place where the memory was allocated, not where you failed to release it.
The cuplrit is almost certainly free_tree. A tree is a recursive data-structure, which means you need to free it recursively. You are only freeing the root node.
Change these lines:
free(t->left);
free(t->right);
to
free_tree(t->left);
free_tree(t->right);
though I'm not sure what you'd provide as ngram. Probably pass in the original.
The point is that you have to navigate down each branch, freeing from the bottom up before releasing the node itself.

segmentation fault 11, while pointer variables

I am trying to take input from console and add it to hash table.
But I'm getting Segmentation fault 11.
So, I debugged the program using gdb-apple.
It is showing that I'm trying access memory I cannot, using the pointer variable.
I think it is something obvious, but I'm missing it
This is what the gdb is displaying
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000008
0x0000000100000986 in CreateHashTable (size=200) at hashing.c:29
29 h->Table[i]->next = NULL;
Here is the code
Header File:
#define LOAD_FACTOR 20
#define INITIAL_SIZE 200
struct HashTable *CreateHashTable(int size);
int HashSearch(struct HashTable *h,int data);
int HashInsert(struct HashTable *h,int data);
int HashDelete(struct HashTable *h, int data);
void Rehash(struct HashTable *h);
int Hash(int data, int size);
struct ListNode
{
int key;
int data;
struct ListNode *next;
};
struct HashTableNode
{
int bcount;
struct ListNode *next;
};
struct HashTable
{
int tsize;
int count;
struct HashTableNode **Table;
};
Implementation file:
#include "hashing.h"
#include<stdio.h>
#include<stdlib.h>
struct HashTable *CreateHashTable(int size)
{
struct HashTable *h;
h = (struct HashTable *) malloc ( sizeof(struct HashTable) );
if(h == NULL)
{
printf("Memory Error");
return NULL;
}
h->tsize = (int) size/LOAD_FACTOR;
printf("h->tsize = %d",h->tsize);
h->count = 0;
h->Table = malloc ( ( sizeof(struct HashTableNode **) ) * (h->tsize) );
if( h->Table == NULL )
{
printf("Memory Error");
return NULL;
}
int i;
for( i=0 ; i < (h->tsize) ; i++)
{
h->Table[i]->next = NULL;
h->Table[i]->bcount = 0;
}
return h;
}
I would paste the rest of file, or Driver file, but I don't see it relevant.
Please tell me why I'm getting the segmentation fault 11
You allocated memory for array of pointers but you didn't allocate memory for members of this array.
for( i=0 ; i < (h->tsize) ; i++)
{
h->Table[i] = malloc(...); //put correct arguments here and check allocation
h->Table[i]->next = NULL;
h->Table[i]->bcount = 0;
}
Your problem is here:
struct HashTableNode **Table;
You want an array of nodes (not a 2d array), change to:
struct HashTableNode *Table;
also change
h->Table = malloc ( ( sizeof(struct HashTableNode **) ) * (h->tsize) );
to
h->Table = malloc(sizeof(struct HashTableNode) * h->tsize);
I think I want an array of pointers to nodes, don't I?
As pointed out by #WhozCraig, there is no reason for the additional level of indirection.
Example A (Pointer):
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *a; /* pointer */
int i, n = 10;
a = malloc(n * sizeof(int)); /* space for 10 ints */
for (i = 0; i < n; i++) {
a[i] = i;
}
for (i = 0; i < n; i++) {
printf("%d\n", a[i]);
}
free(a);
return 0;
}
Example B (Pointer to pointer):
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int **a; /* pointer to pointer*/
int i, n = 10;
a = malloc(n * sizeof(int *)); /* space for 10 pointer to ints */
for (i = 0; i < n; i++) {
a[i] = malloc(sizeof(int)); /* space for 1 int */
*a[i] = i;
}
for (i = 0; i < n; i++) {
printf("%d\n", *a[i]);
free(a[i]);
}
free(a);
return 0;
}
As you can see both do the same thing, but the first one requires less memory and the code is cleaner.
One way to make it easy to remember is:
int * can hold an array
int ** can hold a table (NROWS * NCOLS)
int *** can hold an array of tables

Resources