How to perform deep copy using double poiners? - c

Question read.
In the below code, List used by Stack in-turn used by preOrderTraversal(), of rooted tree, without recursion but using explicit stack,
/* list.h */
typedef struct List{
void **array;
int lastItemPosition;
int size;
}List;
#define INITIAL_LIST_SIZE 50
List *createList(List *list, Op opType){
List *lptr = (List *)malloc(sizeof(List));
void *array = NULL;
if(opType == CREATE_NEW_LIST){
array = malloc(INITIAL_LIST_SIZE*sizeof(void*));
lptr->array = &array;
lptr->array = memset(lptr->array, 0, INITIAL_LIST_SIZE*sizeof(void *));
lptr->lastItemPosition = -1;
lptr->size = INITIAL_LIST_SIZE;
}else if(opType == DOUBLE_THE_LIST){
array = malloc(2*(list->size)*sizeof(void *));
lptr->array = &array;
lptr->array = memcpy(lptr->array, list->array, list->size*sizeof(void*));
lptr->lastItemPosition = list->lastItemPosition;;
lptr->size = 2*(list->size);
}else if(opType == HALF_THE_LIST){
array = malloc(((list->size)/2)*sizeof(void *));
lptr->array = &array;
lptr->array = memcpy(lptr->array, list->array, (list->size/2)*sizeof(void *));
lptr->lastItemPosition = list->lastItemPosition;;
lptr->size = (list->size)/2;
}
return lptr;
}
void insertItem(List *, void *, int);
void *deleteItem(List *, int);
List* createList(List *, Op);
/* Stack.h */
#include"list.h"
typedef struct Stack{
List *arrayList;
}Stack;
void push(void *);
void *pop();
void*top();
Wrt,
lptr->array = memcpy(lptr->array, list->array, list->size*sizeof(void*));
memcpy is passing double pointers. A double pointer is a single pointer to single pointer, so it can be passed to a function that expects a void pointer, But, the actual copy of array of void* should not work
As I actually need to copy the array of void*. if memcpy is called, like,
lptr->array = memcpy(*(lptr->array), *(list->array), list->size*sizeof(void*));
then,
Does memcpy perform copy operation, successfully? How to perform deep copy?

Your existing memcpy statement copies an array of void * values. Each of those void * presumably points to a different memory block, with some arbitrary contents. memcpy does not do anything with that arbitrary content: all you have done is to create a copy of the list of addresses of those blocks, not copied the blocks themselves.
It is hard to see how you can do anything at all with the underlying content, in the snippet of code that we can see here, and that includes copying it. This is because there is no record of the type or size of the content pointed-to by each void *'.
The suggestion you made:
memcpy(*(lptr->array), *(list->array), list->size*sizeof(void*))
will not work for several reasons. It asks memcpy to take the first void * value (not any of the others - that's one problem), and to look at the underlying memory block to which that first pointer points. It copies a certain amount of memory from the source to the destination block. But you have not mentioned allocating any new memory for the new destination block (thereby changing the value of the destination void * itself), so the source and destination are presumably the same address. That's another problem. Also, it uses the wrong size (size of the overall list of void *s, not the size of the memory block in question). That's yet another problem.
The goal you seem to want to achieve cannot be achieved with a single call. Your void *s may (as defined by code we cannot see here) point to consecutive parts of a single contiguous memory blockā€”in which case a single memcpy might appear to work "by accident". But as far as we know, they also might not be arranged like that. They might be separately-allocated chunks of memory all over the place. If so, you're going to need to treat each one separately: loop over the array of pointers, and for each one malloc new space for the copy of the associated block before copying that block. Of course, both to allocate and to copy, you're going to need to have a record of the size of each block.

Related

Where is the error in freeing memory from created hashtable

I am studying C (self-study, not in an educational institution) and have been trying to build a hashtable data structure as part of my learning.
Please refer to this hopefully reproducible example:
#include <stdio.h>
#include <stdlib.h>
struct table_item {
char *name;
char gender;
char *birthdate;
char *address;
};
struct list_node {
struct table_item *data;
struct list_node *next;
unsigned long long hash_key;
};
struct hashtable {
int table_size;
int num_entries;
struct list_node **entries;
};
struct hashtable* init_hashtable(int size);
void free_hashtable(struct hashtable *table);
int main(void)
{
struct hashtable *hashtable = NULL;
int size_entry = 0;
printf("Input hashtable array size: ");
while (size_entry < 1) {
scanf(" %d", &size_entry);
}
hashtable = init_hashtable(size_entry);
free_hashtable(hashtable);
return 0;
}
struct hashtable* init_hashtable(int size) {
struct hashtable* new_table;
if ((new_table = malloc(sizeof(struct hashtable))) == NULL) {
perror("Error: failed to allocate memory for hash table\n");
exit(EXIT_FAILURE);
}
new_table->table_size = size;
new_table->num_entries = 0;
if ((new_table->entries = malloc(size*sizeof(struct list_node))) == NULL) {
perror("Error: failed to allocate memory for hash table array\n");
exit(EXIT_FAILURE);
}
return new_table;
}
void free_hashtable(struct hashtable *table) {
for (int i = 0; i < table->table_size; i++) {
if (table->entries[i] != NULL) {
free_list(table->entries[i]);
table->entries[i] = NULL;
}
}
free(table->entries);
free(table);
}
My issue is that trying to free the table always fails, even if I have not added anything to it.
I used GDB to check the issue. It seems that, in the above for loop, if (table->entries[i] != NULL) always fires (such as when i=0) even when I haven't added anything. This results in my free_list function trying to free inappropriate memory, which is why I get the stack dump.
Somehow it seems that table->entries[i] is actually not NULL but rather has a struct list_node * type, causing the if condition to fire inappropriately. Could somebody please explain to me why this is?
I was hoping that I could use this for loop to go through the entries array and only free memory where malloced nodes exist, but as it stands this will just crash my program. I am not sure how I can alter this to behave as I'd like it to.
Somehow it seems that table->entries[i] is actually not NULL
Indeed, because you never initialized it to NULL.
init_hashtable allocates space using malloc and points table->entries. Now malloc does not initialize the memory it provides. Its contents are garbage, and in particular, there is no reason why it should consist entirely of NULL pointers as your code expects.
If you want table->entries to be full of NULL pointers then you have to explicitly initialize it, either with a loop, or with memset(entries, 0, size*sizeof(struct list_node *)). Or best of all, by calling calloc instead of malloc, which also avoids bugs in case the multiplication size*sizeof(struct list_node *) overflows.
(Technically memset and calloc initialize memory to all-bits-zero, which in theory does not have to correspond to NULL pointers, but it actually does on all systems you are likely to encounter. But to be pedantic, the loop is the only strictly conforming way to do it.)
but rather has a struct list_node * type,
This has nothing to do with types. Types in C are statically determined from declarations, and there is no way for an object to have an unexpected type at runtime. The type of table->entries[i] is struct list_node * no matter what. The question is about the value of that object; you expect it to be NULL but it's not. "Null pointers" are not a separate type in C; NULL is simply a value that a pointer of any type may have.
As Avi Berger points out, there is another bug in that the size calculation in the malloc should be size*sizeof(struct list_node *) not sizeof(struct list_node). Each element is not a struct list_node but rather a pointer. In this case a struct list_node is larger than a pointer, so it's just wasting memory and not causing any other harm, but it should be fixed.
Somehow it seems that table->entries[i] is actually not NULL but rather has a struct list_node * type, causing the if condition to fire inappropriately. Could somebody please explain to me why this is?
You dynamically allocate space for table->entries. The initial contents of that allocated space are unspecified, so until you assign values to its contents, it is unsafe to have any particular expectations about them. In particular, you cannot assume that any or all elements will contain null pointers.
If you want to rely on those values to tell you something about what kind of cleanup needs to be performed, then you should set them all to appropriate values, I guess NULL, immediately after allocating the space.
Note also that there are null pointer values of every pointer type, so being null and having type struct list_node * are not mutually exclusive.

Pointers to structs in C vs pointers to arrays

Do pointers to structures in C work differently than other pointers?
For example in this code:
typedef struct node {
int data;
struct node *next;
} node;
void insert(node **head, int data) {
node *new_node = malloc(sizeof(node));
new_node->data = data;
new_node->next = *head;
*head = new_node;
}
int main() {
node *head = NULL;
insert(&head, 6);
Why do I have to use a pointer to a pointer and can't use the variable head in the insert function like in this example with arrays:
void moidify(int *arr) {
*arr = 3;
}
int main() {
int *array = malloc(8);
*array = 1;
*(array + 1) = 2;
moidify(array);
}
Here I don't have to pass &array to the function.
There is no difference. If you want to change the value of the variable you send in to function in such a way that the change is visible in the function that called function, you need to supply its address to function, which is what you do when taking the address of head.
In moidify(array) you send in a pointer to the first element in array which is why modifying the array data works. If you would like to modify the array variable itself (by making it potentially point somewhere else), you would have to take its address too. Example:
void moidify(int **arr) {
*arr = realloc(*arr, 128);
if(*arr == NULL) {
perror(__func__);
exit(1);
}
}
int main() {
int *array = malloc(8);
*array = 1;
*(array + 1) = 2;
moidify(&array);
}
You must understand how pointers works to get this one.
Here, the variable array is not properly speaking, an array. It's a pointer toward a memory space, of size 8 * sizeof(int). It contains only an address. From this address you can access the values of the array, you move using this address, to the rightfully memory space you want to fill or read.
Once that understood, when you call the moidify function, you are not passing the array. Nor the memory space. You are passing, the address of the memory space. The function gets a copy of the given address, in the argument variable int *arr.
Hence, you can use it the same way you use it from the main function.
If you wanted to change the address toward which the array variable would go, you would need to specify &array to the receiving function, which would then use an int ** argument variable.
Your example with struct is similar to this last part I just described, you want to change toward which address head is pointing, so, you need to give &head to the function. To get the address of head, and be able to modify the contained address.
You use an address, to access the memory space called head, to modify the address inside the memory space called head, which point toward another memory space, where your struct truly belongs.

Allocating more than what you need and freeing the extra space

I was wondering if it was possible to over allocate and free excess that you have allocated? I was thinking something along the lines of
/*
This is a pseudo program, just to show what I am talking about, there should be more
checks to prevent overflow.
*/
typedef struct {
struct Node *neighbor
int value
} Node;
...
Node create_tree(char* content, int size) {
int mem_index = 0
Node *last_node;
// size > sizeof(Node)
void base* = malloc(size);
while( mem_index < size) {
Node nptr* = (Node)(base + mem_index);
if(last_node != NULL) nptr->neighbor = last_node;
last_node = nptr;
mem_index += sizeof(Node);
nptr->value = (int)(base + mem_index)
(nptr->value)* = get_some_content(content);
mem_index += sizeof(int);
}
free((base + mem_index));
}
Basically this program over allocates and begins casting the memory into structures and then writes to those structures. It points the pointers within the structure to further points in the memory. It then writes another structure past all of that unit it is done with writing. I am wondering if this is possible, and if it is, is it good practice? I have heard under allocating is an issue, and I am not a fan of allocating every time I want to create a new structure if I am going to be creating them dynamically.
You can use realloc to shrink the memory block to the desired size:
base2 = realloc(base, mem_index);
If the call is successful, then the memory after base + mem_index will be freed.
BTW. Using pointer of type void* for arithmetic is GCC extension. You should use char*.
Note that returned base2 may not be same as the original base. You update all existing references to base with base2.

Correct way to use malloc() and free with linked lists

I am trying to understand malloc() better when it comes to linked list. Does this create memory for the pointer to the list as well as the fields inside of it?
Such as:
SomeStruct * someStructPtr = (SomeStruct *) malloc(sizeof(SomeStruct));
Alongside this, if I am trying to free this node AND the fields inside of it. Do I need to walk through all the fields (see code below). Does this just free the pointer (created from the line above) or does it free the pointer and and the fields.
free(someStructPtr);
For a more direct example. I have a struct of List and I'm trying to allocate space for this struct AND it's fields when it is created. I want to make sure I am creating, deleting, and using stdrup() correctly. My code is below:
Struct Declaration:
typedef struct ListNode_st
{
char * str;
struct ListNode_st * next;
} List;
Create Node:
List * List_createNode(const char * str){
List * listPointer = (List *) malloc(sizeof(List));
//make sure there was enough memory
if(listPointer == NULL)
return NULL;
//malloc for next
listPointer.next = (List *) malloc(sizeof(List *));
if(listPointer.next == NULL)
return NULL;
listPointer.next = NULL;
//malloc for str
listPointer.str = strdup(str);
//make sure enough space for the string to be copied
if(listPointer.str == NULL)
return NULL;
//return value
return listPointer;
}
Delete Node:
void List_destory(List * list){
//base case -- (last item)
if(list == NULL)
return;
//recurse case -- (there are more items)
List_destroy(list->next);
if(list->str != NULL)
free(list->str);
if(list->next != NULL)
free(list->next);
free(list);
}
Please don't cast the return value from malloc().
malloc(sizeof(SomeStruct))
allocates enough memory for one struct, and you then have to initialise every field within the struct.
calloc(1, sizeof(SomeStruct))
does the same but every byte of the struct is initialised to 0. malloc() and calloc() know nothing about your struct, they simply allocate the amount of memory you asked for. They return a void* pointer so that they can be used with any data type, about which they neither know nor care.
When you come to free() the allocated memory, the same applies - free() knows nothing about your struct, or even if it is a struct. It's up to you to free() any memory allocation within that struct, before you free() the memory for the struct. It does not free a struct. It frees the memory where the struct is.
So the answer is yes, you do need to walk through the whole data structure, otherwise any nested memory allocation pointers will be lost, resulting in memory leak.
List * List_createNode(const char * str){
List * listPointer = (List *) malloc(sizeof(List));
if(listPointer == NULL)
return NULL;
listPointer->next = NULL;
listPointer->str = strdup(str);
if(listPointer->str == NULL){
free(listPointer);
return NULL;
}
return listPointer;
}
void List_destory(List * list){
if(list == NULL)
return;
List_destroy(list->next);
free(list->str);
free(list);
}
Let's warm up a little before we tackle your question.
int x = 42;
Where does the memory of x come from? Is it allocated? Where? If this line is inside a function, the answer is: it is an "automatic" variable and the memory it uses is on the stack.
int * y = NULL;
Where does the memory for y come from now? There was no call to malloc() here and yet, y exists.
By now, you should be able to answer the first part of your question. malloc() is not allocating the memory for your pointer in this case.
struct Node
{
struct Node * next;
int value;
};
void InitNode( Node *node, int value )
{
if(NULL != node)
{
node->next = NULL;
node->value = value;
}
}
// Not on HEAP, not on stack! Where?
// This one gets its memory from "initvars" section.
int foo = 69;
int main( int argc, const char * argv[] )
{
struct Node n1; // instance located on stack...
InitNode(&n1); // no malloc() to be seen...
// Instance located on HEAP, but n2, the pointer is located on stack,
// just like an int x = 42 would be.
struct Node *n2 = malloc(sizeof(struct Node));
}
So, obviously in order to de-mystify what malloc() does requires to understand the different types of memory and how to deal with it.
So far we saw "automatic" aka "stack memory", we saw "initvars" memory. And we saw "heap" memory. malloc() is the function you use to allocate memory on the heap.
Last not least, there are yet other types of memory I will not mention here.
Does this create memory for the pointer to the list as well as the fields inside of it?
Given your struct type
typedef struct ListNode_st
{
char * str;
struct ListNode_st * next;
} List;
the following call will create memory for an instance of that struct:
List *l = malloc( sizeof *l ); // note no cast, operand of sizeof
l points to a block of memory large enough to contain two pointers; however, nothing's been allocated for either str or next to point to. You would have to allocate memory for the string and the next node separately:
l->str = malloc( N * sizeof *l->str ); // allocate N characters
or
l->str = strdup( str );
Note that in most linked list implementations, you don't allocate memory for next when you create a new node; that field is meant to point to another, previously allocated node in the list. You will set it when you insert a node following the current node.
Alongside this, if I am trying to free this node AND the fields inside of it. Do I need to walk through all the fields (see code below). Does this just free the pointer (created from the line above) or does it free the pointer and and the fields.
You need to free any allocated members first before deleting the entire node, such as
free( l->str );
free( l );
Freeing l does not free the memory that l->str points to.

Using malloc in C to allocate space for a typedef'd type

I'm not sure exactly what I need to use as an argument to malloc to allocate space in the table_allocate(int) function. I was thinking just count_table* cTable = malloc(sizeof(count_table*)), but that doesn't do anything with the size parameter. Am I supposed to allocate space for the list_node_t also? Below is what I am working with.
In the .h file I'm given this signature:
//create a count table struct and allocate space for it
//return it as a pointer
count_table_t* table_allocate(int);
Here are the structs that I'm supposed to use:
typedef struct list_node list_node_t;
struct list_node {
char *key;
int value;
//the next node in the list
list_node_t *next;
};
typedef struct count_table count_table_t;
struct count_table {
int size;
//an array of list_node pointers
list_node_t **list_array;
};
count_table* cTable = malloc(sizeof(count_table*))
is wrong. It should be
count_table* cTable = malloc(sizeof(count_table));
Also, you must allocate memory for list_node_t also seperately.
EDIT:
Apart from what Clifford has pointed about allocating memory for the list node, I think the memory allocation should also be taken care for the char *key inside of the list node.
Your suggestion: count_table* cTable = malloc(sizeof(count_table*)) would only allocate space for a pointer to a count_table.
You'd need
count_table* cTable = malloc(sizeof(count_table) ) ;
Each list node would be separately allocated and cTable->size and cTable->list_array and the last list_node_t::next updated accordingly. Maintaining a pointer to the last node added would make adding nodes faster.
I am not sure why count_table::list_array is of type list_node_t** rather than just list_node_t* (and equally called list_array rather than just list). Is it your intention that it is both an array and a list at the same time? That would be somewhat redundant. The member need only be a pointer to the first node, successive nodes are then accessed via list_node::next
Given that the int is a "size" parameter for the created count_table_t, it appears that you are supposed to both allocate the count_table_t itself, as well as initialise its members.
Initialising the list_array member also involves a memory allocation, so it would look like:
count_table_t *table_allocate(int size)
{
count_table_t *table = malloc(sizeof *table);
int i;
table->size = size;
table->list_array = malloc(size * sizeof table->list_array[0]);
for (i = 0; i < size; i++)
table->list_array[i] = NULL;
return table;
}
However, you also need to check for some error conditions: the multiplication of size by sizeof table->list_array[0] could overflow, and either of the malloc() calls could fail. So the function should actually look like this:
count_table_t *table_allocate(int size)
{
count_table_t *table;
int i;
/* Check for overflow in list allocation size */
if (size < 0 || size > (size_t)-1 / sizeof table->list_array[0])
return NULL;
table = malloc(sizeof *table);
if (table == NULL)
return NULL;
table->size = size;
table->list_array = malloc(size * sizeof table->list_array[0]);
if (table->list_array == NULL) {
free(table);
return NULL;
}
for (i = 0; i < size; i++)
table->list_array[i] = NULL;
return table;
}
(Note that (size_t)-1 is a constant equal to the maximum value of a size_t, which is the type of the parameter to malloc()).
In addition to the other posters who point out that you're only allocating enough space for the pointer, not the space the data you want will occupy, I strongly urge you to do things like this:
count_table* cTable = malloc(sizeof(*cTable));
This will help you in case the type of cTable ever changes, you won't have to adjust two parts to that line, just the type.

Resources