malloc array of structs in a struct - c

I have a struct called course and each course has multiple nodes (another struct 'node').
The number of nodes it has varies but I am given that number from a file that I am reading this information from, so that number sits in a variable.
So I need a malloc inside the struct. But I am confused. I know you can have arrays in structs but I don't know where to put the code that creates the malloc array since my struct is in my header file. Here's my code at the moment. I realize it looks wrong, I just don't know how I can fix it and where to initialize the malloc array.
struct course {
char identifier[2];
int num_nodes;
struct node *nodes;
nodes = (struct nodes*)malloc(num_nodes*sizeof(struct node));
};
struct node {
int number;
char type[2];
};
I want to be able to do something like:
struct node a_node;
struct course a_course;
a_course.nodes[0] = a_node;
etc...
I haven't used much C, this is the first time I've ever tried using dynamic arrays in C. My experience all comes from Java, and of course Java doesn't really use pointers in the same way as C so it's all a tad confusing for me.
So some help would be much appreciated, thanks a lot :)

The easiest approach is to create a function which initialises the struct:
void init_course(struct course* c, const char* id, int num_nodes)
{
strncpy(c->identifier, id, sizeof(c->identifier));
c->num_nodes = num_nodes;
c->nodes = calloc(num_nodes, sizeof(struct node));
}
For symmetry, you could also then define a destructor
void destroy_course(struct course* c)
{
free(c->nodes);
}
These would have usage like
struct course c;
init_course(&c, "AA", 5);
/* do stuff with c */
destroy_course(&c);

The purpose of malloc (or calloc - which I prefer to use for structs) is to dynamically allocate the memory at runtime. So, your struct should look like this, since it is an object definition:
struct course {
char identifier[2];
int num_nodes;
struct node *nodes;
};
Somewhere else in your program that uses the course struct, you will need to allocate memory (i) for any course objects you create and (ii) any node objects in that course.
e.g.
main()
{
// lets say 1 course
struct course *my_course;
my_course = calloc(1, sizeof(struct course));
// lets say 3 nodes in that course
struct node *my_nodes;
my_nodes = calloc(3, sizeof(struct node));
my_course.num_nodes = 3;
my_course.nodes = my_nodes;
//...
// clean up
free(my_nodes);
free(my_course);
}
Now, you are good. Make sure to free the memory before exiting.

it is also possible to direct allocate the structs in structs this way:
first declare your struct:
struct course {
char identifier[2];
int num_nodes;
struct node *nodes;
};
then in your program
main(){
int i;
struct course *c;
c = malloc(sizeof(struct course));
c->num_nodes = 3;
c->nodes = malloc(sizeof(struct node)*c->num_nodes);
for(i=0; i<c->num_nodes; i++)
c->nodes[i] = malloc(sizeof(struct node));
//and free them this way
for(i=0; i<c->num_nodes; i++)
free(c->nodes[i]);
free(c->nodes);
free(c);
}
or do it the way above what ever you like

Related

Implementing a simple linked list in C without malloc

All the implementations I have seen online use pointer to declare nodes and then will use malloc to create space for them like this:
struct Node
{
int data;
struct Node *next;
};
int main()
{
struct Node* head = NULL;
struct Node* second = NULL;
struct Node* third = NULL;
head = (struct Node*)malloc(sizeof(struct Node));
second = (struct Node*)malloc(sizeof(struct Node));
third = (struct Node*)malloc(sizeof(struct Node));
...
But I can also create the same without pointers and malloc like this:
struct node {
int id;
struct node* next;
};
struct node head = {0, NULL};
struct node one = {1, NULL};
struct node two = {2, NULL};
struct node tail = {3, NULL};
int main(){
head.next = &one;
one.next = &two;
two.next = &tail;
...
My question is, why the 1st method is mostly the one used, why do we need to declare each node as pointer and why do we need malloc?
(Just to point out I know why struct Node *next; is declared as pointer int the struct declaration).
You should do this with local variables, not global ones, but the general idea would be the same. You should also steer towards having arrays and not heaps of otherwise unrelated variables:
struct node {
int id;
struct node* next;
};
int main(){
struct node nodes[4];
for (int i = 0; i < 4; ++i) {
nodes[i].id = (3 - i);
if (i != 0) {
nodes[i].next = &nodes[i-1];
}
}
return 0;
}
Where something like that assembles them in reverse order for convenience, but they're all grouped together in terms of memory initially.
malloc is used because you often don't know how many you're going to have, or they get added and removed unpredictably. A general-purpose solution would allocate them as necessary. A specialized implementation might allocate them as a single block, but that's highly situational.
Here the lifespan of nodes is within that function alone, so as soon as that function ends the data goes away. In other words:
struct node* allocateNodes() {
struct node nodes[10];
return &nodes; // Returns a pointer to an out-of-scope variable, undefined behaviour
}
That won't work. You need a longer lived allocation which is precisely what malloc provides:
struct node* allocateNodes() {
struct node *nodes = calloc(10, sizeof(struct node));
return nodes; // Returns a pointer to an allocated structure, which is fine
}
The problem is if you malloc you are responsible for calling free to release the memory, so it becomes more work.
You'll see both styles used in code depending on the required lifespan of the variables in question.
If you know ahead of time exactly how many items will be in your list, then you're probably better off using an array rather than a list. The whole point of a linked list is to be able to grow to an unknown size at runtime, and that requires dynamic memory allocation (i.e., malloc).

Allocating memory for nested linked list + using scanf

I'm struggling with allocating a memory for my linked list which is embedded in it's parent linked list - nested structure.
Structure declaration:
typedef struct parent
{
int x;
struct embed
{
int y;
int l;
struct embed *next;
}EMBED;
struct parent *next;
}PARENT;
Allocating memory for parent list:
PARENT *head = NULL;
PARENT *temp = (PARENT*)malloc(sizeof(PARENT));
What can't I figure out is how can I connect to that embedded list for allocating. Any ideas?
Also when we get to allocating memory and getting connection to that embedded list, I want to use a scanf function to store some data into that list but I do not know the connection declaration. How does it work, can someone explain?
Just so you know what am I working on, it is a school project for searching in a tree - starting from point A, finish at point B when inputs are numbers and in between them is a distance variable. So basically I want to find the shortest way (less calculations = short execution time) from getting to point B.
Thanks for suggestions.
Once the structure is properly defined, you can allocate an embedded list element like so:
temp->EMBED.next = malloc(sizeof(struct embed));
You don't need that inner typedef inside the struct definition. In fact, my GCC doesn't like it. This works:
typedef struct parent
{
int x;
struct embed
{
int y;
int l;
struct embed *next;
} embed;
struct parent *next;
} PARENT;
With this, you can allocate and fill a list with something like this:
PARENT p;
/* build up a list */
p.embed.next = NULL;
for (i = 0; i < 5; i++) {
struct embed *new = malloc(sizeof *new);
new->next = p.embed.next;
printf("enter a number:\n");
scanf("%d", &new->y);
p.embed.next = new;
}

A Hashset that holds a generic linked list that holds a generic linked list

This is my data structure for an Assignment I'm doing in class. I'm supposed to implement a a hash set that holds a string of linked lists. Each of those individual linked lists holds an int. My list is generic, if it works, using (void* data) like this:
typedef struct NodeStruct {
void *data;
struct NodeStruct* next;
struct NodeStruct* prev;
} NodeStruct;
// Rename NodeStruct* as NodePtr
typedef NodeStruct* NodePtr;
typedef struct ListStruct {
int elementType;
NodePtr first;
NodePtr last;
NodePtr current;
} ListStruct;
// ListHndl is just a ListStruct* renamed.
First question: Right now, I"m using memcpy(list->data, data, list->elementType).
I was wondering.. is it okay do just store it directly, like list->data = data?
This is my hash set struct:
typedef struct HashStruct {
int size;
int load;
ListHndl *chain; //An array of Linked Lists.
} HashStruct;
typedef HashStruct* HashHandle
HashHandle new_hashset(int size) {
HashHandle tempHash = malloc (sizeof (HashStruct));
assert (tempHash != NULL);
tempHash->size = size;
tempHash->load = 0;
tempHash->chain = malloc (sizeof (ListHndl) * size);
assert(tempHash->chain != NULL);
for (int i = 0; i < size; i++) {
tempHash->chain[i] = newList(sizeof(char*));
tempHash->chain[i]->data = malloc(sizeof (ListHndl)); // Error here
}
return tempHash;
}
This is the error that I'm getting.
hash.c: In function ‘new_hashset’:
hash.c:28:27: error: dereferencing pointer to incomplete type
tempHash->chain[i]->data = malloc(sizeof (ListHndl));
^
Second question: I'm not sure how I'm supposed to be allocating memory for these linked lists, which is probably why I got this error.
Am I even implementing this data structure correctly? If more information is needed, please let me know. Thank you!
First question: Right now, I"m using memcpy(list->data, data, list->elementType). I was wondering.. is it okay do just store it directly, like list->data = data?
That depends on what 'data' is pointing to. It is quite common to list->data = data when 'data' is pointing to memory allocated from the heap,
Second question: I'm not sure how I'm supposed to be allocating memory for these linked lists, which is probably why I got this error.
For the typedefs outlined in the question, you will need to allocate memory for:
Each new node: newNode=malloc(sizeof(NodeStruct))
Each node payload: newNode->data = malloc(sizeof(int))
Am I even implementing this data structure correctly?
It is difficult to say with the limited code provided. Of course, there are many ways to accomplish the assigned task; including those ways that are easier to understand, as well as those which are specifically tuned for performance.

C struct question

I have a interface documented like this:
typedef struct Tree {
int a;
void* (*Something)(struct Tree* pTree, int size);
};
Then as I understand I need to create instance of it, and use Something method to put the value for 'size'.
So I do
struct Tree *iTree = malloc(sizeof(struct Tree));
iTree->Something(iTree, 128);
But it keeps failing to initialize. Am I doing this right?
Howcome the first member of the Something method is pointer to the very same struct?
Can anyone explain please?
Thanks
You have to set Something to something since it is only a function pointer and not a function. The struct you created with malloc just contains garbage and struct fields need to be set before it is useful.
struct Tree *iTree = malloc(sizeof(struct Tree));
iTree->a = 10; //<-- Not necessary to work but you should set the values.
iTree->Something = SomeFunctionMatchingSomethingSignature;
iTree->Something(iTree, 128);
Update
#include <stdlib.h>
#include <stdio.h>
struct Tree {
int a;
//This is a function pointer
void* (*Something)(struct Tree* pTree, int size);
};
//This is a function that matches Something signature
void * doSomething(struct Tree *pTree, int size)
{
printf("Doing Something: %d\n", size);
return NULL;
}
void someMethod()
{
//Code to create a Tree
struct Tree *iTree = malloc(sizeof(struct Tree));
iTree->Something = doSomething;
iTree->Something(iTree, 128);
free(iTree);
}
This is a poor man's virtual function. The initial parameter is roughly equivalent to C++'s this pointer in a member function. And you must manually set the function pointers before calling them, whereas C++ virtual functions are set up by the compiler.
The member Tree::Something is never initialized. You allocate space for a Tree, but allocation is different from initialization, and your allocated Tree contains only unmeaningful bits.

Why this code doesn't allocate memory in C?

Updated question is here
Memory allocation problem in HashTable
I'm working on making a HashTable in C. This is what I've done. I think I'm going on a right path but when I'm trying to
main.c
HashTablePtr hash;
hash = createHashTable(10);
insert(hash, "hello");
insert(hash, "world");
HashTable.c
HashTablePtr createHashTable(unsigned int capacity){
HashTablePtr hash;
hash = (HashTablePtr) malloc(sizeof(HashTablePtr));
hash->size = 0;
hash->capacity = capacity;
ListPtr mylist = (ListPtr)calloc(capacity, sizeof(ListPtr)); /* WHY IT DOESN'T ALLOCATE MEMORY FOR mylist HERE?? */
mylist->head = NULL;
mylist->size = 0;
mylist->tail = NULL;
hash->list = mylist;
return hash;
ListPtr is a LinkedList ptr
List.h
typedef struct list List;
typedef struct list * ListPtr;
struct list {
int size;
NodePtr head;
NodePtr tail;
};
...
...
HashTable.h
typedef struct hashtable * HashTablePtr;
typedef struct hashtable HashTable;
struct hashtable {
unsigned int capacity;
unsigned int size;
ListPtr *list;
unsigned int (*makeHash)(unsigned int, void *);
};
...
...
When I run my debugger, I see no memory being allocated to myList. In above example, my attempt is to make it an array of 10 lists.
Please help me to solve this.
I'm not that expert in C, if that helps.
calloc(capacity, sizeof(ListPtr)
should be
calloc(capacity, sizeof(List)
I think there are a whole host of problems here. You haven't included the error you getting so, I will list a couple:
hash = (HashTablePtr) malloc(sizeof(HashTablePtr*)); - You are allocating the size of a HashTable **, which is four bytes, you need to allocate the size of the underlying object.
ListPtr mylist = (ListPtr* )calloc(capacity, sizeof(ListPtr)); - Again, your are allocating the size of the pointer rather than the underlying list object.
HashTablePtr createHashTable(unsigned int capacity)){ - You are probably getting a compile error here with the extra parens and the inconsistent number of parameters.
Personally I am not a huge fan of using typedefs, especially when you are a beginner. I think that may be partially what is confusing you. You are better avoiding things like:
typedef struct hashtable * HashTablePtr;
Using to many typedefs will make your code harder to read since you will need to constantly look up what they are referring too.
The main problem is that you were allocating the memory for the size of a hashtable/list pointer and not for the size of their respected structures. I think the code below shows this well. You will also want to check if you allocations worked. If malloc, calloc, realloc. etc. fail they return NULL. If this happens and you do not check for this case you will get a segfault error and your program will crash.
Also follow the c99 standard, and put all of your variable declarations at the start of the function.
c99 std
malloc manpage
struct hashtable *
createHashTable(unsigned int capacity){
struct hashtable *hash;
struct list *mylist;
/* You want to allocate size of the hash structure not the size of a pointer. */
hash = malloc(sizeof(struct hashtable));
// always make sure if the allocation worked.
if(hash == NULL){
fprintf(stderr, "Could not allocate hashtable\n");
return NULL;
}
hash->size = 0;
hash->capacity = capacity;
/* Unless you need the memory to be zero'd I would just use malloc here
* mylist = calloc(capacity, sizeof(struct list)); */
mylist = malloc(capacity * sizeof(struct list));
if(mylist == NULL){
fprintf(stderr, "Could not allocate list\n");
free(hash); /* free our memory and handle the error*/
return NULL;
}
mylist->head = NULL;
mylist->size = 0;
mylist->tail = NULL;
hash->list = mylist;
return hash;
}
Also remember to free you list before you free your hashtable:
free(myhash->list);
free(myhash);
You are allocating a contigous block of ListPtr's, but you actually want to allocate space for the all the structures rather than just pointers (ListPtr) to those structures:
calloc(capacity, sizeof(List));
I agree with gman's comment about not hiding pointers. When coding in C, I never typdef a List * as a ListPtr. It makes the code harder to understand.

Resources