Dynamically Allocating Memory to an array of Struct Nodes - c

I am trying to create an array of structs, with dynamically allocated memory,
Here's the struct definition I'm using:
struct node {
int key;
double probability;
struct node *parent;
struct node *children[255];
};
Here is the declaration and initialization:
int base_nodes = sizeof(X)/sizeof(*X);
while ((base_nodes - 1)%(D-1) != 0){
printf("Incrementing base\n");
base_nodes++;
}
printf("base_nodes:\t%d\n", base_nodes);
struct node **nodes = malloc(base_nodes * sizeof(struct node));
if (nodes) {
printf("Size of nodes:\t%llu\n", sizeof(nodes));
} else { printf("Failed to allocate memory\n"); return 1;}
Where X is another dynamically allocated Array of numbers defined before I call it here.
AFAIK, base_nodes is being calculated correctly, however the Size of nodes: is reporting 8, rather than 10. I have tried base_nodes less than 8 and it also returns 8.
Could someone explain why this happens? And how to do it properly?
The program I'm making is a D-ary Huffman code generator given a PMF.
I also attempted to realloc later on in the program and it seems to have had no effect:
nodes = realloc(nodes, ((sizeof(nodes) + 1) * sizeof(struct node)));
if (nodes) {
printf("New size:\t%llu\n", sizeof(nodes));
} else { printf("Not enough memory\n"); }

You're trying to obtain the number of elements of type struct node, allocated dynamically, using the operator sizeof() on the pointer itself, which will just return the size of a pointer on your machine, which is 8 bytes as it seems to be a 64 bit machine.
I think you're confused by the fact that when you allocate some memory statically in an array you can use sizeof() operator to return the number of elements allocated, i.e.
myType a[N];
number_of_elements = sizeof(a)/sizeof(myType)

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.

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.

Creating a graph by using adjacency matrix

Here is my stucture
struct node{
int V,E;
int **adj;
};
Here is my code to create a graph:
struct node* create()
{
int i,j,x,y;
struct node *G=malloc(sizeof(struct node));
printf("Write the number of vertex and edges\n");
scanf("%d%d",&G->V,&G->E);
G->adj=malloc(sizeof(int)*(G->V * G->V));
if(!G->adj){
printf("Out of memory\n");
return;
}
for(i=0;i<G->V;i++)
for(j=0;j<G->V;j++)
G->adj[i][j]=0;
printf("\nWrite the source node and destination: ");
for(i=0;i<G->E;i++){
scanf("%d%d",&x,&y);
G->adj[x][y]=1;
G->adj[y][x]=1;
}
return(G);
}
and I am storing the pointer returned by this function in another pointer like this:
int main()
{
struct node *G=create();
}
When I compile the program, I'm asked for the number of vertex and edges but as soon as I enter the values, my program crashes. I want to know the reason. Is this because of memory allocation failure?
C99 style variable length arrays are only useful with local variables or arguments. So, you have the two classic C methods available to implement a 2D array.
Array of pointers:
That's what your struct looks like. With that, you need separate allocations for the pointer array and data:
G->adj = calloc(G->V, sizeof (int*));
assert(G->adj != NULL); /* need assert.h for this */
for (i=0; i<G-V; ++i)
{
G->adj[i] = calloc(G->V, sizeof (int));
assert(G->adj[i] != NULL);
}
It's a bit easier on memory to do one bulk allocation of the array data and then use pointer arithmetic to set the G->adj[] pointers, but the above gives the idea that, as far as C is concerned, each row is a separate array.
Just one bulk array, with explicit cell location calculation done on each access. This is what C does internally with nested arrays.
Change the type of adj to just int* and then:
G->adj = calloc(G->V * G->V, sizeof (int));
assert(G->adj != NULL);
That's it. Now when you access an element, use G->adj[i*G->V + j], instead of G->adj[i][j]. Macros may help with readability.

Wrong struct member values after pointer assignment [duplicate]

This question already has answers here:
Changing address contained by pointer using function
(5 answers)
Closed 5 years ago.
I'm trying to allocate memory for and initialize members of a struct.
In a function which takes a pointer to the struct and some other parameters (used in other members), I allocate the memory for the struct itself and its nodes member and initialize the other members. Printing the size and len members within the initialization function outputs the correct values, but testing them after the function outputs random garbage.
Why is this behavior occurring and what can I do to fix it?
Struct definitions:
struct node_t {
int priority;
void *data;
};
struct pqueue {
int len,size,chunk_size;
struct node_t *nodes;
};
Initialization function:
int alloc_pq(struct pqueue *q,int init_size,int chunk_size){
// allocate for struct
if((q=(struct pqueue*) malloc(sizeof(struct pqueue)))==NULL){
perror("malloc");
return -1;
}
// set initial sizes
q->len=0;
q->chunk_size=chunk_size;
q->size=init_size;
if(init_size>0){
// allocate initial node memory (tried malloc here too)
if((q->nodes=(struct node_t*) realloc(q->nodes,init_size*sizeof(struct node_t)))==NULL){
perror("realloc");
return -1;
}
}
printf("%lu %d %d\n",sizeof(*q),q->size,q->len); // DEBUG
return q->size;
}
In main function:
struct pqueue q;
...
alloc_pq(&q,n,0);
printf("%lu %d %d\n",sizeof(q),q.size,q.len); // DEBUG
Output (second last number is always > 32000, last is seemingly random):
24 67 0
24 32710 -2085759307
The way you do things is making no changes. You passed address and then overwrote it.
Any changes you make to q will be lost when that function ends. Solution would be to either take a pointer variable in main() and pass it's address.
struct pqueue* q;
...
alloc_pq(&q,n,0);
Change alloc_pq accordingly. Something like
int alloc_pq(struct pqueue **q,int init_size,int chunk_size){
// allocate for struct
if((*q=malloc(sizeof(struct pqueue)))==NULL){
perror("malloc");
return -1;
}
// set initial sizes
(*q)->len=0;
(*q)->chunk_size=chunk_size;
(*q)->size=init_size;
if(init_size>0){
// allocate initial node memory (tried malloc here too)
if(((*q)->nodes= realloc((*q)->nodes,init_size*sizeof(struct node_t)))==NULL){
perror("realloc");
return -1;
}
}
printf("%lu %d %d\n",sizeof(*q),(*q)->size,(*q)->len); // DEBUG
return (*q)->size;
}
Your use of realloc is wrong. Use a temporary vcariable to hold the result and check whether it returns NULL or not.
Casting the result of malloc,realloc is not needed. Free the memory allocated when you are done working with it. Check the return value of malloc,realloc.
struct node_t* temp= realloc((*q)->nodes,init_size*sizeof(struct node_t)));
if( temp == NULL ){
perror("realloc");
exit(EXIT_FAILURE);
}
(*q)->nodes = temp;

node is giving garbage value

i am doing c program of binary tree while inserting the node to tree after 2 or 3 nodes the child node having garbage value and crashing i am doing in xcode any idea...
Bnode createTreeNode()
{
Bnode node=(Bnode)malloc(sizeof(Bnode));
return node;
}
Bnode addTreeNode(Bnode inNode, char *inData)
{
int compareValue;
if (inNode == NULL)
{
inNode = createTreeNode();
inNode->leftNode=NULL;
inNode->rightNode=NULL;
stpcpy(inNode->data,inData);
}
else if((compareValue=strcmp(inData,inNode->data))==0)
{
inNode->count=inNode->count+1;
}
else if(compareValue>1)
{
inNode->rightNode=addTreeNode(inNode->rightNode,inData);
}
else
{
inNode->leftNode = addTreeNode(inNode->leftNode,inData);
}
return inNode;
}
this is how i creating node and inserting it to tree.
Bnode node=(Bnode)malloc(sizeof(Bnode)); //[1]
return node;
Argument of malloc is the size of the dynamic memory to be allocated.
You have provided size of the pointer to the struct as the argument instead of size of the struct itself.
As a result, less memory is allocated to Bnode and eventually you are bound to get garbage values and segmentation faults.
Change it to something like
Bnode node = malloc(sizeof(struct _bnode));
//where Bnode is pointer to struct _bnode
P.S.: [1] Explicit casts (Bnode) not required in C.
You declared a pointer for your node, but you didn't actually allocate any storage for it, so you have a dangling pointer. You need to call malloc() (or calloc()) for each new node, in order to allocate storage.

Resources