How to append to a pointer array in c - c

I have an array of pointers to structs and I'm trying to find a way to fill the first NULL pointer in an array with a new pointer to a struct. i.e. I want to add a new element onto the end of an array.
I tried a for loop like this:
struct **structs;
int i;
for(i = 0; i < no_of_pointers; i++) {
if (structs[i] == NULL) {
structs[i] = &struct;
}
}
In theory, this would go through the array and when it finds a null pointer it would initialise it. I realise now that it would initialise all null pointers, not just the first, but when I run it it doesn't even do that. I've tried a while loop with the condition while(structs[i] != NULL) and that just goes on forever, making me think that the issue is with how I'm using NULL.
What is the correct way to add a new element to an array of this kind?
Is there some function like append(structs, struct) that I don't know of?
Thanks!

The length of an array in C is fixed, you cannot change it after you defined an array, which means you cannot add an element to the end of an array. However, unless you defined a constant array, you could assign new values to elements of an array. According to your question description, I believe this is what you want.
Also note that, as other already pointed it out in comments, struct is a keyword of C, therefore
you cannot use it as a type name (as you did in struct **structs)
you also cannot use it as a variable name (as you did in structs[i] = &struct;)
Here is one way to do it:
define an array properly
struct struct_foo **structp;
structp = malloc (no_of_elements * sizeof(*structp));
if (structp == NULL) {
/* error handle */
}
Note, at here the elements of structp is not initialized, you need to initialize them properly. That is what we are going to do in step 2.
do something with structp, maybe initialize all its elements to NULL or some no-NULL value
find the first no-NULL element in structp, and assign it a new value
struct struct_foo foo;
for (i = 0; i < no_of_elements; i++) {
if (structp[i] == NULL) {
structp[i] = &foo;
break;
}
}
Note that this foo also is uninitialized, you may want to initialize it first, or you could initialize it later.

According to man malloc:
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
void *reallocarray(void *ptr, size_t nmemb, size_t size);
...
The reallocarray() function changes the size of the memory block
pointed to by ptr to be large enough for an array of nmemb elements,
each of which is size bytes. It is equivalent to the call
realloc(ptr, nmemb * size);
Try implementing a system like this
struct **structs;
int new_struct() {
static int i = 0; // index of last allocated struct
i++;
struct *structp = malloc(sizeof(struct)); // new structure
// initialize structp here
reallocarray(structs, i, sizeof(struct));
structs[i] = structp;
return i; // use structs[index] to get
}
Then you may invoke new_struct(), which resizes the structs array and appends structp to it. The important part is that
a) create_struct returns the index of the newly created struct, and
b) it stores a static int i, which keeps track of the size of the structs.

Related

Is there a way to create a dynamic type assignment in C

I am working to create a set of functions in C that will allow a dynamically growing array. In this example I have create a struct with a variable titled len that stores the active length of the array, another variable titled size that stores the total length of the array assigned during initialization, and another variable titled array which is a pointer to the memory containing the array data. In this example the variable array is initialized in the struct as an integer. Within the function titled int_array I initialize the array and and return the struct. Within that function I call the init_int_array function that does the heavy lifting. In addition, I have another function titled append_int_array that checks the memory allocation and assigns another chunk of memory if necessary and then appends the array with a new index/variable. As you can see, this example is hard coded for an integer, and I will need to repeat these lines of code for every other data type if I want an array to contain that type of data. There has got to be a way to instantiate the struct so that the variable array can be a different data type so that I do not have to repeat all lines of code for every data type, but I am not sure what that method is. Any help would be appreciated. The code is shown below. NOTE: I also have a function to free the array memory after use, but I am omitting it since it is not relevant to the question.
array.h
#ifndef ARRAY_H
#define ARRAY_H
#include<stdlib.h>
#include<stdio.h>
typedef struc
{
int *array;
size_t len;
size_t size;
}Array;
void init_int_array(Array, size_t num_indices);
Array int_array(size_t num_indices);
void append_int_array(Array *array, int item);
#endif /* ARRAY_H */
Array.c
void init_int_array(Array *array, size_t num_indices) {
/* This function initializes the array with a guess for
the total array size (i.e. num_indices)
*/
int *int_pointer;
int_pointer = (int *)malloc(num_indices * sizeof(int));
if (int_pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
free(int_pointer);
exit(0);
}
else {
array->array = int_pointer;
array->len = 0;
array->size = num_indices;
}
}
Array int_array(size_t num_indices) {
/* This function calls init_int_array to initialize
the array and returns a struct containing the array
*/
Array array;
init_int_array(&array, num_indices);
return array;
}
void append_int_array(Array *array, int item) {
/* This function adds a data point/index to the array
and also doubles the memory allocation if necessary
to incorporate the new data point.
*/
array->len++;
if (array->len == array->size){
array->size *= 2;
int *int_pointer;
int_pointer = (int *)realloc(array->array, array->size * sizeof(int));
if (int_pointer == NULL) {
printf("Unable to reallocate memory, exiting.\n");
free(int_pointer);
exit(0);
}
else {
array->array = int_pointer;
array->array[array->len - 1] = item;
}
}
else
array->array[array->len - 1] = item;
}
A simple solution is rewrite your header like this:
typedef struct
{
void *array; // buffer
size_t len; // amount used
size_t elem; // size of element
size_t size; // size of buffer
} Array;
void init_array(Array *, size_t num_indices, size_t elem);
Array array(size_t num_indices, size_t elem);
void append_array(Array *array, void *item);
The changes to your code would be as follows:
Remove references to int in the name.
Make all inputs be to arbitrary type using void *.
Use array.elem instead of sizeof(int).
The biggest change is that elements to append will be passed by pointer, not by value.
Cast the buffer to whatever type you need to access elements.
Cast the buffer to char * internally to do pointer math on it.
Here is a sample calling sequence you could use:
Array buf = array(10, sizeof(int));
for(int i = 0; i < 3; i++) {
append_array(&buf, &i); // Remember that buf knows sizeof(int)
}
printf("Second element (of %d) is %d\n", buf->len, ((int *)buf->array)[1]);
C is a strongly- and statically-typed language without polymorphism, so in fact no, there is no language-supported form of dynamic typing. Every object you declare, every function parameter, every struct and union member, every array element has a specific type declared in your source code.
Some of the things you can do:
use a typedef or a preprocessor macro to provide indirection of the data type in question. That would allow you to have (lexically) one structure type and one set of support functions that provide for your dynamically-adjustable array to have any one element type of the user's choice, per program.
use preprocessor macros to template the structure type and support functions so that users can get separate versions for any and all element types they want. This might be usefully combined with _Generic selection.
define and use a union type for use as the array's element type, allowing use of any of the union's members' types. With a little more work, this can be made a tagged union, so that objects of different types in the same array could be supported. The cost, however, is wasted space and worse memory efficiency when you use members having smaller types.
use void * or maybe uintmax_t or unsigned char[some_largish_number] as the element type, and implement conversions to and from that type. This has some of the disadvantages of the union alternative, plus some complications surrounding the needed conversions. Also, there is no type that can be guaranteed large enough to accommodate all other data types. Nor even all built-in data types, though this is a more realistic goal.
use void as the formal element type (possible only with dynamic allocation and pointers, not with an array-style declaration). Add a separate member that recoirds the actual size of the elements. Implement wrappers / conversions that support use of that underlying structure in conjunction with various complete data types. This is described in more detail in another answer.

How to differentiate empty and 0 in an int array in C?

I'm a beginner of C and now I'm learning pointer and dynamic memory allocation. I want to write a simple program to create empty arrays and check for the existence of a given number. Here's my code:
/* create an empty array pointer */
int* createArray(){
int *a = (int*) malloc(sizeof(int));
return a;
}
void findArrayElement(int *list, int element){
int i;
int len = (sizeof(list) / sizeof(int));
if (sizeof(list) == 0) {
printf("NO\n");
return;
}
for (i=0; i<len; i++) {
if (list[i] == element) {
printf("YES\n");
return;
}
}
printf("NO\n");
}
int main(int argc, const char * argv[]) {
int *p;
p = createArray();
printf("size of int is: %lu\n", sizeof(int));
printf("size of p is: %lu\n", sizeof(p));
printf("LENGTH of p is: %lu\n", ARRLENGTH(p));
findArrayElement(p, 2);
findArrayElement(p, 0);
return 0;
}
But when I run the program, I always get 'YES' when I looking for 0, so
Is there a way to differentiate integer 0 and a complete empty array?
Also I'm not sure whether my function createArray() is a correct way to create an empty array.
Thanks guys.
Is there a way to differentiate integer 0 and a complete empty array?
How do you define an empty array? Once you allocate a memory chunk and assign it to a pointer, it already has some value (which is undefined in case of alloc). The most used way to mark a pointer as not used or not allocated os to assign NULL to it.
Also I'm not sure whether my function createArray() is a correct way to create an empty array.
sizeof returns the number of bytes which the given object (or type) occupies in the memory. In your case sizeof(list) returns 8 as it is a pointer.
In oder to allocate an array, the function has to receive its size. Currently it always allocates size for one integer only.
Edit: Adding example.
/* create an empty array pointer */
int* createArray(size_t size)
{
return (size ? (int*) malloc(sizeof(int)*size) : NULL);
}
So now the returned pointer should be 'coupled' with the size of the array. Which means that each function that receives an array as a parameter should receive also its size.
sizeof returns the memory size of the array pointer, regardless of contents.
edit: if it exists in memory, it will be nonzero.
edit 3: removed inaccurate information, see the comments about creating a variable to record the length. Also from comments, note that your createArray function is creating an array for exactly 1 integer. In C, arrays are of fixed length. So this Array will always be the same size (whether you stored something in it or not). sizeof(pointer) will always return the memory allocated for the pointer, not the memory allocated for the array at which it is pointing.

Assign array without element by element copy?

I have a function which creates an array, of say, size 5.
Is it possible for the function to accept a pointer (or maybe it needs a pointer to a pointer?) and then point said pointer at an array, so that when the callee then looks at the pointer, it can see all values of the array.
Something along the lines of this (except this will not work):
#define LENGTH 5
void assignArray(int *pointer)
{
int arr[LENGTH] = {0,1,2,3,4};
// Point the pointer at the array, without manually copying each element
pointer = arr;
}
void main()
{
int *pointer;
pointer = malloc(sizeof(int) * LENGTH);
assignArray(pointer);
int i;
for (i = 0 ; i < LENGTH ; i++) printf("%d\n", pointer[i]);
}
C assign array without element by element copy
In C, arrays (compile-time allocated) cannot be assigned. You need to copy the elements from one array to another.
To avoid element-by-element copy, you can copy the whole array all at a time using library function.
I'm not very sure what you want to ask here, but it seems, you need to do memcpy() to achieve your goal.
If you have a secondary array arr to copy from, you can write
memcpy( pointer, arr, ( (sizeof arr[0]) * LENGTH ));
The code to do what you are describing might look like:
#define LENGTH 5
void assignArray(int **pp)
{
static int arr[LENGTH] = {0,1,2,3,4};
// Point the pointer at the array, without manually copying each element
*pp = arr;
}
int main()
{
int *pointer;
assignArray(&pointer);
for (int i = 0 ; i < LENGTH ; i++)
printf("%d\n", pointer[i]);
}
Note that one does not simply point *pp at a non-static local variable arr. That is because int arr[] = .... would go out of scope when assignArray returns.
If you want each call to assignArray to "return" a different array then of course you will have to allocate space and use memcpy each time you want to make a copy of the original array.
int arr[LENGTH] = {0,1,2,3,4}; will be stack allocated, so attempting to return the pointer to any of its elements will give you undefined behaviour as the whole thing will be out of scope when the function returns.
If you want to change what a pointer is pointing to then use 2 levels of indirection ** (i.e. pass a pointer to a pointer). You'll need to allocate the array arr on the heap using malloc or something similar.
As you are trying to do it, it is not possible due to the fact that your local arr is saved to the stack and is cleaned up after the function assignArry finished. As already mentioned you need to memcpy.
This answer will have two parts:
As mentioned in other answers, this is now how you're supposed to do it. A common construct in similar code is:
void assignArray(int *dest, size_t size)
{
int i;
// initialize with some data
for (i=0; i<size; i++)
dest[i] = i;
}
This way you're not wasting space and time with an intermediate buffer.
Second part of this answer is about wrapping arrays in a struct. It's a silly trick, that in a way achieves exactly what you asked, and also something that you probably don't want because of extra data copying.
Example code:
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 5
struct foo { int arr[LENGTH]; };
struct foo assignArray()
{
struct foo bar = { .arr = {0,1,2,3,4} };
/* return the array wrapper in struct on stack */
return bar;
}
int main()
{
struct foo *pointer;
pointer = malloc(sizeof(*pointer));
*pointer = assignArray(); /* this will copy the data, not adjust pointer location */
int i;
for (i = 0 ; i < LENGTH ; i++) printf("%d\n", pointer->arr[i]);
return 0;
}

How can I set a certain value to a member of a struct within multiple functions?

i am a beginner so please cut me some slack on this one. So I have two functions and a struct in a header file I am currently working with.
This is the struct:
typedef struct ArrayList
{
// We will store an array of strings (i.e., an array of char arrays)
char **array;
// Size of list (i.e., number of elements that have been added to the array)
int size;
// Length of the array (i.e., the array's current maximum capacity)
int capacity;
} ArrayList;
Here is the first function, which creates and dynamically allocates memory for an array of strings. Capacity is the length of the internal array and size is the current size (how many strings are in the array which is essentially 0.)
ArrayList *createArrayList(int length){
char **array = NULL;
ArrayList *n;
int size = 0;
if (length > DEFAULT_INIT_LEN)
{
array = malloc(sizeof(int) * length);
n->capacity = length;
}
else
{
array = malloc(sizeof(int) * DEFAULT_INIT_LEN);
n->capacity = DEFAULT_INIT_LEN;
}
if (array == NULL)
panic("ERROR: out of memory in Mylist!\n");
n->size = size;
printf("-> Created new ArrayList of size %d\n", n->capacity);
return *array;
When I try to implement a pointer to the capacity member of the ArrayList struct inside another function within the same file, it is uninitialized instead of set as the value from the previous function. I.e. in createArrayList, n->capacity is equal to 10, but when used in printArrayList it is uninitialized and a random number appears such as 122843753.:
void printArrayList(ArrayList *list)
{
printf("\n%d", list->capacity);
return NULL;
}
My question is, how can I make it so all these functions "share" the same value when referring to the struct members. I.E. the first function prints -> Created new ArrayList of size 10, and the second function prints 10 as well. Also, I have to do this without changing the struct function itself. Sorry if this is a poorly worded question, but I can further clarify if it is confusing. Thanks in advance!
I see a couple of major issues with this code, in createArrayList you are returning array which is a char ** but you should be returning an ArrayList * which is what n is. So it looks like you want to assign array to n->array. The next issue is that n is an ArrayList * but you do not allocate memory for n.

How can I make a pool with pointers in C?

I'm making my library, and just when I thought understanding the pointers syntax, I just get confused, search on the web and get even more confused.
Basically I want to make a pool, here is what I actually want to do:
the following points must be respected :
when I add an object to the pool, the pointers of the current array to the objects are
added to a new array of pointers + 1 (to contain the new object).
the new array is pointed by "objects" of my foo structure.
the old array is free'ing.
when I call the cleanup function, all the object in the pool are
free'd
How should I define my structure ?
typedef struct {
int n;
(???)objects
} foo;
foo *the_pool;
here's the code to manage my pool :
void myc_pool_init ()
{
the_pool = (???)malloc(sizeof(???));
the_pool->n = 0;
the_pool->objects = NULL;
}
void myc_push_in_pool (void* object)
{
if (object != NULL) {
int i;
(???)new_pointers;
the_pool->n++;
new_pointers = (???)malloc(sizeof(???)*the_pool->n);
for (i = 0; i < the_pool->n - 1; ++i) {
new_pointers[i] = (the_pool->objects)[i]; // that doesn't work (as I'm not sure how to handle it)
}
new_array[i] = object;
free(the_pool->objects);
the_pool->objects = new_array; // that must be wrong
}
}
void myc_pool_cleanup ()
{
int i;
for (i = 0; i < the_pool->n; ++i)
free((the_pool->objects)[i]); // as in myc_push_in_pool, it doesn't work
free(the_pool->objects);
free(the_pool);
}
Note: the type of objects added to the pool are not known in advance, so i should handles all pointers as void
any feedback would be very welcomed.
A straight answer to your question would be: use void *. This type is very powerful as it allows you to put any kind of pointer in your pool. However, it's up to you to do the correct casts when retrieving a void * pointer from your pool.
Your struct would look like this
typedef struct {
int n;
(void **)objects
} foo;
foo *the_pool;
As in, an array of pointers.
Your malloc:
new_pointers = (void **)malloc(sizeof(void *)*the_pool->n);
There is an performance issue here. You could simply allocate an array of a fixed size, and only reallocate if the number of elements exceeds a predefined load factor (= number used/ max size)
Also, instead of allocating a new pointer each time you add something to your pool, you could just use realloc (http://www.cplusplus.com/reference/cstdlib/realloc/)
the_pool->objects = (void **)realloc(the_pool->objects, the_pool->n* sizeof(void*));
Realloc tries to increase the current allocated area, without the need to copy everything. Only if the function cannot increase the allocated area contiguously will it allocate a new area and copy everything.
Firstly, you already answered your "What should the type of foo.objects be?" question: void *objects;, malloc already returns void *. Your struct needs to store the size_t item_size;, too. n should probably also be a size_t.
typedef struct {
size_t item_count;
size_t item_size;
void *objects;
} foo;
foo *the_pool;
You could use a home-grown loop, but I'd consider memcpy to be a more convenient way to copy your old items to your new space, and the new item to it's new space.
Dereferencing a void * is a constraint violation, as is pointer arithmetic on a void *, so new_pointers will need to be a different type. You need a type that points to objects of the right size. You could use an array of the right number of unsigned char, like so:
// new_pointers is a pointer to array of the_pool->item_size unsigned chars.
unsigned char (*new_pointers)[the_pool->item_size] = malloc(the_pool->item_count * sizeof *new_pointers);
// copy the old items
memcpy(new_pointers, the_pool->objects, the_pool->item_count * sizeof *new_pointers);
// copy the new items
memcpy(new_pointers + the_pool->item_count, object, sizeof *new_pointers);
Remember, free() is only for pointers returned by malloc(), and there should be a one-to-one correspondence: Each malloc() should be free()d. Look how you malloc: new_pointers = malloc(sizeof(???)*the_pool->n); ... What makes you think you need a loop (in myc_pool_cleanup) to free each item, when you can free them all in one foul swoop?
You could use realloc, but you otherwise seem to be handling malloc/memcpy/free *in myc_push_in_pool* flawlessly. Lots of people tend to mess up when writing realloc code.

Resources