Initialize void pointer to point to an array - c

Suppose I have the following:
typedef struct {
int itemSize;
int count;
void *list;
} Mystruct;
Mystruct *InitStruct(int itemSize, int count)
{
Mystruct *my = malloc(sizeof(Mystruct));
my->itemSize = itemSize;
my->count = count;
//What is the best way to initialize list? For example:
//my->list = malloc(count * sizeof(void *)); OR
//my->list = malloc(count * sizeof(itemSize));
}
//The following should return a pointer to the element stored at a given index
void *Retrieve(const MyStruct *my, int index)
{
void *item;
//What is the best way to return a pointer to the item at the given index from
//my->list?
}
Mystruct is similar to an array and void *list is supposed to store the elements or pointers to the elements. Mystruct *InitStruct is a function that initializes a Mystruct pointer and void *Retrieve is a function that returns a pointer to the element stored at a given index.
First, how should I initialize void* list? Should it hold the actual elements or be an array of pointers pointing to the elements?
Second, using the void *Retrieve function, how do I return a pointer to the element stored at a given index in my->list?

On the first point, if all elements are the same size, as that itemSize name suggests, then adding one level of indirection (having list point to pointers to items, rather than to items directly) seems to have no added value, so I'd use my->list = malloc(count * itemSize);.
On the second point, (char*)my->list + itemSize*index should work. You may first want to check that index < my->count, of course (maybe you want to return NULL in that case rather than an invalid pointer).

Related

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.

Initializing an array of pointers to structs containing a double pointer in c

I have a header class containing the following struct definitions:
struct Entry {
int key;
char *value;
};
typedef struct Entry Entry;
struct Heap {
int capacity;
int size;
Entry **elements;
};
typedef struct Heap Heap;
And, I'm trying to write a function makeHeap that "returns a pointer to some newly allocated Heap with the given capacity, a size of 0, and an elements array allocated with the given capacity."
The elements array is what I'm not entirely sure about. It's supposed to contain pointers (references) to Entry objects. Which I am not sure if I'm doing correctly here. In order to make an array that holds references to Entry objects, I declare a double pointer array (due to the Entry having a pointer in it) and then I initialize elements iteratively, and then set my newly created heap's elements pointer to a pointer of the **elements array I just built.
I'm not getting any compile errors, but I honestly don't know if I am doing this correctly. Any input would be greatly appreciated. I did some searches but couldn't find the case where a struct was defined quite in the way mine is with the double pointer array Entry** elements.
Also, as far the syntax between Entry** elements and Entry **elements are these interchangeable? As in they are both declaring an array that holds double pointers of type Entry?
Heap *makeHeap(int capacity) {
//Make the heap
Heap* theHeap = calloc(1, sizeof(Heap));
//set its capacity to param
theHeap->capacity = capacity;
//inital size is 0
theHeap->size = 0;
//elements contains pointers (references) to Entry objects.
Entry **elements[capacity];
//iterate capacity times allocating an entry reference for each element to be placed
int i = 0;
for (; i < capacity; i++) {
elements[i] = calloc(1, sizeof(Entry));
}
theHeap->elements = *elements;
return theHeap;
}
you'll need to malloc the elements of the heap as well, you can't just assign an array to it in a function as it will become invalid once the makeHeap() function exit. Here's your code with the correction:
Heap* makeHeap(int capacity) {
//Make the heap
Heap* theHeap = calloc(1, sizeof(Heap));
//set its capacity to param
theHeap->capacity = capacity;
//inital size is 0
theHeap->size = 0;
//elements contains pointers (references) to Entry objects.
theHeap->elements = calloc(capacity,sizeof(Heap*));
//iterate capacity times allocating an entry reference for each element to be placed
int i = 0;
for(; i < capacity; i++) {
theHeap->elements[i] = calloc(1, sizeof(Entry));
}
return theHeap;
}
Note: Make sure to free everything once you are done with it:
Heap* test = makeHeap(10);
//Do your stuff with the heap...
for(size_t i = 0;i<test->capacity;i++){
//Note: free the 'char* value' if you malloced them
free(test->elements[i]);
}
free(test->elements);
free(test);
You seem to have never allocated memory for elements of type Entry**. The position of the asterisks does NOT matter to answer that last question! They are declaring double pointers so really declaring 2D arrays or an array of Entry pointers, NOT "an array that holds double pointers of type Entry".
Entry** elements[capacity]; should be Entry** elements[capacity] = malloc(sizeof(Entry*) * capacity) as well.

C - dynamically allocating a circular-buffer of structs within a struct

I am attempting to develop a dynamically-allocated circular-buffer in C using two structs. One holds detailed information and another is essentially used as a pointer from main to the circular-buffer structure (as there will be multiple arrays allocated at runtime).
Since it is a circular-buffer, I have a pointer "next" which points to the next item in the array (so last array index points to the first, etc.)
These are the two struct objects I have:
typedef struct {
int a;
int b;
struct1 *next; // pointer to next struct1 object in array
} struct1;
typedef struct {
struct1 *curr;
struct1 *start = NULL;
struct1 *end = NULL;
} struct2;
I then have my initialize function that is called from main to initiate a new circular-buffer.
This is the part where I am not entirely sure what to do.
#define minSize 10
struct2 * initialize()
{
struct2 **newBuf = malloc(sizeof(*newBuf));
newBuf->malloc(sizeof(*newBuf->quotes) * newBuf->minSize);
// set the start pointer
newBuf.curr[0] = newBuf->start;
newBuf.curr[0]->next = NULL;
for (int i = 1; i < minSize; i++)
{
struct1 *new = NULL;
newBuf.curr[i] = new; // make index i = NULL
// have the previous index point to the "next" current
if (i > 0)
newBuf.curr[i-1]->next = newBuf.curr[i];
}
// connect last index with first
newBuf.curr[minSize - 1]->next = newBuf.curr[0];
// set the end pointer
newBuf->end = newBuf->start;
return newBuf;
}
From searching I found this answer on how to initialize an array of structs within a struct by using malloc for initially allocating the space, but am confused how my code would line up since I have pointers to define start and end of the circular-buffer defined in struct2, as well as the next pointer as part of struct1.
Additionally, I've chosen to define ***newBuf* instead of **newBuf* as I was considering it as a pointer to pointers in a way (thinking about singly-linked lists). Though, please correct me if I am wrong.
I've done dynamically allocated circular-buffers in Java, but not C nor C++, so I am having a hard time figuring out the differences in how to initialize everything. I'm basically stuck at this mess and not sure where to go next.
Any help that can be given would be much appreciated!
The reason you're running into trouble is because you're trying to have the pointer to a pointer, rather than just using an ordinary pointer. You want to access the pointer that is contained at the address pointed to by the first pointer. As it stands you're trying to access a member that is outside of the memory space of the original pointer's address (which is only as large as an address). And then you're running into trouble because you aren't initializing your array 'curr' either. Another thing I did that doesn't really matter but helps you understand pointers is made your array a pointer- which is how arrays work in C. The array is simply the address of the first member of the array, and when you index into the array, it just adds an offset to that address = index * sizeof(yourstruct).
What you want is
typedef struct {
struct1 *curr;
struct1 *start = NULL;
struct1 *end = NULL;
} struct2;
#define minSize 10
struct2* initialize()
{
struct2 *newBuf = (struct2 *) malloc(sizeof(struct2));
newBuf->curr = (struct1 *) malloc(sizeof(struct1) * minSize);
// set the start pointer
newBuf.curr[0] = newBuf->start;
newBuf.curr[0]->next = NULL;
for (int i = 1; i < minSize; i++)
{
struct1 *new = (struct1 *) malloc(sizeof(struct1));
newBuf.curr[i] = new;
newBuf.curr[i-1]->next = newBuf.curr[i];
}
// connect last index with first
newBuf.curr[minSize - 1]->next = newBuf.curr[0];
// set the end pointer
newBuf->end = newBuf->start;
return newBuf;
}

Pointer to an array of pointers to Linked lists

I have been at this problem for the last 6 hours and have been hitting google like mad to no avail.
Right I need a pointer to an array. This array contains pointers to Linked lists. Im going to have to malloc it since I dont know the array size until runtime.
LList **array
This was my first thought but this just gives me a pointer to an array of LList. Or atleast that is my understanding. Can someone give me a hand?
EDIT: Some info on how it would be used: I am implementing a very basic hash table. There is a structure that contains a pointer to an array of pointers to linked lists.
It needs to be a pointer to the array so that when I resize the table. I can just change the pointer to point to the larger table.
It sounds like you're on the right track.
LList **array;
array = malloc(num_ptrs * sizeof(LList*));
array is now an array of pointers to LList, and elements such as array[3] will be a pointer to a LList.
Arrays and pointers are very similar in C (but not identical!), as shown by the classic example: *(array + 2) is mostly equivalent to array[2].
Edit:
When you need to resize the table, you'll just need to realloc the additional space:
LList **new_array;
new_array = realloc(old_array, new_size * sizeof(LList*));
new_array and old_array may or may not be the same pointer afterwards, but either way new_array is guaranteed to be a pointer to enough space to hold the new array (or NULL if the memory couldn't be allocated)
2nd Edit:
As user411313 alluded, if you want the actual pointer to the array, you'll need to take the address of the array:
LList ***p_array;
p_array = &array;
A pointer to an object, is basically the same as a pointer to an array.
int * blah; // an int pointer. It could point to an array of ints, or a single int.
int ** blah; // a pointer to an int pointer. It could point to something that points to an int, or it could be pointing to an array of pointers to single ints, or it could be a pointer that points to an array of ints.
It all depends on how you use it.
A pointer to a pointer can also be an array of pointers.
int nLists; /* number of lists*/
LList **array;
array = (LList **)malloc(nLists * sizeof(LList *));
will make array be an array of pointers to LList. Then array[i] will give you the pointer to the i-th linked list in the array.
if you have to write your own linked list, you can do this.
typedef struct LLNode {
LLNode* next;
int data;
} LLNode;
LLNode* linkedList = null; // a linked list
LLNode** linkedListArray = (LLNode**) malloc( arraySize* sizeof(LLNode*) );
LLNode*** pointerToLListArray = &linkedListArray;
with a linked list library:
LList* linkedListArray = (LList*) malloc( arraySize* sizeof(LList) );
LList** pointerToLListArray = &linkedListArray;
typedef struct LList LList;
struct LList {
int value;
LList *next; };
LList *(*p)[3]; /* pointer to an array of 3 pointers to LList */
LList ll1 = {11};
LList ll2 = {22};
LList ll3 = {33};
size_t sizeofarray = sizeof*p/sizeof**p; /* calc arraysize at runtime here */
p = malloc( sizeofarray * sizeof**p ); /* allocate space for each LList-pointer in array */
(*p)[0] = &ll1;
(*p)[1] = &ll2;
(*p)[2] = &ll3;
/* test output here: */
printf("\n%d\n%d\n%d", ((*p)[0])->value,((*p)[1])->value,((*p)[2])->value);
free(p);

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