I have a C struct:
typedef struct {
Dataset *datasets;
int nDatasets;
char *group_name;
enum groupType type;
} DatasetGroup;
It has a constructor function like this:
DatasetGroup * new_DatasetGroup(char *group_name, enum groupType type, enum returnCode *ret)
{
DatasetGroup *dg;
dg = (DatasetGroup *) malloc(sizeof(DatasetGroup));
if (dg == NULL)
{
*ret = EMEMORY_ERROR;
}
// Allocate space for a few datasets
dg->datasets = malloc(sizeof(Dataset) * INCREMENT);
if (dg->datasets == NULL)
{
*ret = EMEMORY_ERROR;
}
dg->group_name= malloc(sizeof(char) * strlen(group_name));
strcpy(dg->group_name, group_name);
dg->type = type;
groupCount++;
return dg;
}
I want to dynamically create an array of these structs. Whats the best way to do this?
So far I have something like:
DatasetGroup * make_array(){
DatasetGroup *dg_array;
// Allocate space for a few groups
dg_array = (DatasetGroup *) malloc(sizeof(DatasetGroup) * INCREMENT);
return dg_array;
}
void add_group_to_array(DatasetGroup *dg_array, ...){
// Add a datasetgroup
DatasetGroup *dg = new_DatasetGroup(...);
// groupCount - 1 as the count is incremented when the group is created, so will always be one ahead of the array index we want to assign to
dg_array[groupCount - 1] = dg;
if (groupCount % INCREMENT == 0)
{
//Grow the array
dg_array = realloc(dg_array, sizeof(DatasetGroup) * (groupCount + INCREMENT));
}
}
But this doesnt seem right....
any ideas?
A few suggestions:
You have groupCount being incremented by the constructor function of the struct. This means you can only have one array of the struct that uses your array function. I would recommend having the array be responsible for managing the count.
To that affect if you want to have a managed array I would create a struct for that and have it keep both the pointer to the array,the number of objects and the size of the array (e.g. the maximum number of structs it can currently hold)
If you keep proper track of how many elements you have and the size of the array you can replace groupCount % INCREMENT == 0 with something like groupCount == arraySize which is a lot more intuitive in my opinion.
You can avoid the second malloc in the constructor all together by having the array be an array of the elements instead of an array of pointers. The constructor than then just initialize the struct members instead of allocating memory. If you are doing this a lot you will be avoiding a lot of memory fragmentation.
Finally, while this depends on your application, I usually recommend when you realloc do not increase by a constant but instead of by a multiple of the current array size. If say you double the array size you only have to do log_2 n number of reallocs with n being the final array size and you waste at most half of memory (memory is generally cheap, like I said it depends on the application). If that is wasting to much memory you can do say 1.5. If you want a more detailed explanation of this I recommend this Joel on Software article, the part about realloc is about 2/3 down.
Update:
A few others things:
dg = (DatasetGroup *) malloc(sizeof(DatasetGroup));
if (dg == NULL)
{
ret = EMEMORY_ERROR;
}
// Allocate space for a few datasets
dg->datasets = malloc(sizeof(Dataset) * INCREMENT);
As previously pointed out is very bad as you will us dg even if it is NULL. You probably want to exit right after detecting the error.
Furthermore you are setting ret but ret is passed by value so it will not be changed for the caller if the callee changes it. Instead you probably want to pass a pointer and dereference it.
Update 2: Can I give an example, sure, quick not so much ;-D.
Consider the following code (I apologize if there are any mistakes, still half asleep):
#include <stdio.h>
#include <stdlib.h>
#define LESS_MALLOCS
#define MAX_COUNT 100000000
typedef struct _foo_t
{
int bar1;
int bar2;
} foo_t;
void foo_init(foo_t *foo, int bar1, int bar2)
{
foo->bar1 = bar1;
foo->bar2 = bar2;
}
foo_t* new_foo(int bar1, int bar2)
{
foo_t *foo = malloc(sizeof(foo_t));
if(foo == NULL) {
return NULL;
}
foo->bar1 = bar1;
foo->bar2 = bar2;
return foo;
}
typedef struct _foo_array_t
{
#ifdef LESS_MALLOCS
foo_t *array;
#else
foo_t **array;
#endif
int count;
int length;
} foo_array_t;
void foo_array_init(foo_array_t* foo_array, int size) {
foo_array->count = 0;
#ifdef LESS_MALLOCS
foo_array->array = malloc(sizeof(foo_t) * size);
#else
foo_array->array = malloc(sizeof(foo_t*) * size);
#endif
foo_array->length = size;
}
int foo_array_add(foo_array_t* foo_array, int bar1, int bar2)
{
if(foo_array->count == foo_array->length) {
#ifdef LESS_MALLOCS
size_t new_size = sizeof(foo_t) * foo_array->length * 2;
#else
size_t new_size = sizeof(foo_t*) * foo_array->length * 2;
#endif
void* tmp = realloc(foo_array->array, new_size);
if(tmp == NULL) {
return -1;
}
foo_array->array = tmp;
foo_array->length *= 2;
}
#ifdef LESS_MALLOCS
foo_init(&(foo_array->array[foo_array->count++]), bar1, bar2);
#else
foo_array->array[foo_array->count] = new_foo(bar1, bar2);
if(foo_array->array[foo_array->count] == NULL) {
return -1;
}
foo_array->count++;
#endif
return foo_array->count;
}
int main()
{
int i;
foo_array_t foo_array;
foo_array_init(&foo_array, 20);
for(i = 0; i < MAX_COUNT; i++) {
if(foo_array_add(&foo_array, i, i+1) != (i+1)) {
fprintf(stderr, "Failed to add element %d\n", i);
return EXIT_FAILURE;
}
}
printf("Added all elements\n");
return EXIT_SUCCESS;
}
There is a struct (foo_t) with two members (bar1 and bar2) and another struct that is an array wrapper (foo_array_t). foo_array_t keeps track of the current size of the array and the number of elements in the array. It has an add element function (foo_array_add). Note that there is a foo_init and a new_foo, foo_init takes a pointer to a foo_t and new_foo does not and instead returns a pointer. So foo_init assumes the memory has been allocated in some way, heap, stack or whatever doesn't matter, while new_foo will allocate memory from the heap. There is also a preprocess macro called LESS_MALLOCS. This changes the definition of the array member of foo_array_t, the size of the initial array allocation, the size during reallocation and whether foo_init or new_foo is used. The array and its size have to change to reflect whether a pointer or the actually element is in the array. With LESS_MACRO defined the code is following my suggestion for number 4, when not, it is more similar to your code. Finally, main contains a simple micro-benchmark. The results are the following:
[missimer#asus-laptop tmp]$ gcc temp.c # Compile with LESS_MACROS defined
[missimer#asus-laptop tmp]$ time ./a.out
Added all elements
real 0m1.747s
user 0m1.384s
sys 0m0.357s
[missimer#asus-laptop tmp]$ gcc temp.c #Compile with LESS_MACROS not defined
[missimer#asus-laptop tmp]$ time ./a.out
Added all elements
real 0m9.360s
user 0m4.804s
sys 0m1.968s
Not that time is the best way to measure a benchmark but in this case I think the results speak for themselves. Also, when you allocate an array of elements instead of an array of pointers and then allocate the elements separately you reduce the number of places you have to check for errors. Of course everything has trade-offs, if for example the struct was very large and you wanted to move elements around in the array you would be doing a lot of memcpy-ing as opposed to just moving a pointer around in your approach.
Also, I would recommend against this:
dg_array = realloc(dg_array, sizeof(DatasetGroup) * (groupCount + INCREMENT));
As you lose the value of the original pointer if realloc fails and returns NULL. Also like your previous ret, you should pass a pointer instead of the value as you are not changing the value to the caller, just the callee which then exits so it has no real affect. Finally, I noticed you changed your function definition to have a pointer to ret but you need to dereference that pointer when you use it, you should be getting compiler warnings (perhaps even errors) when you do try what you currently have.
You could do two things, either you dynamically create an array of struct pointers, then call your new function to create N datagroups, or you could dynamically request memory for N structures at once, this would mean your N structures would be contiguously allocated.
Datagroup **parry = malloc(sizeof(datagroup *) * N)
for (int i = 0; i < N; i++){
parry[i] = //yourconstructor
}
Or
//allocate N empty structures
Datagroup *contarr = calloc(N, sizeof(Datagroup))
The second method might need a different initialization routine than your constructor, as the memory is already allocated
Related
I am working on a series of C functions to allow a user to dynamically build an array. The core of the library resides in the Array struct which contains a pointer variable array that contains the array data, len which contains the length of the array, size, which is the total memory allocation for the array, elem, which contains the memory allocation per indices, and pointer variables name and dtype which contains strings describing the name of the array and the type of the array. For the moment I have constrained the scope so that only int, float, double, and char arrays can be considered.
Thus far I have defined, and individually tested the following functions;
array_mem_alloc which contains code that allocates memory for an array.
init_array which is a wrapper around array_mem_alloc that instantiates an Array struct, determines the data type and returns an Array data type to a user.
append_array which allows a user to dynamically grow an array one index at a time, or add an already defined array.
free_array which frees all memory and resets struct variables
int_array_val which typecasts the data at an index and returns to user. I have versions of this function for all relevant data types, but for this problem I will only use this version.
find_int_array_indices which looks for where a specific integer exists in the array and records the index number into another array which is returned to the user.
For the purposes of testing find_int_array_indices I am calling init_array for a variable titled arr_test and appending it with 7 integers int a[7] = {6, 1, 3, 6, 6, 4, 5}. I pass the Array container arr_test to the find_int_array_indices function and everything works fine, which also returns another Array container titled p. However, when I try to retrieve the integer variables with the int_array_val function it fails, because it does not recognize the variable array->dtype as containing the string "int". However, when I test the container inside of find_int_array_indices and in the main function, the variable does contain the string "int". This tells me that I probably have a pointer error, but I do not see it. Any advice would be very useful. I am wondering if I need to go back to the beginning and define name and dtype as fixed length arrays in the Array struct instead of as pointer variables.
array.h
typedef struct
{
void *array; // Pointer to array
size_t len; // Active length of array
size_t size; // Number of allocated indizes
int elem; // Memory consumption per indice
char *name; // The array name
char *dtype; // A string representing the datatype
} Array;
void array_mem_alloc(Array *array, size_t num_indices);
Array init_array(char *dtype, size_t num_indices, char *name);
int append_array(Array *array, void *elements, size_t count);
void free_array(Array *array);
int int_array_val(Array *array, int indice);
Array find_int_array_indices(Array *array, int integer);
array.c
void array_mem_alloc(Array *array, size_t num_indices) {
// Determine the total memory allocation and assign to pointer
void *pointer;
pointer = malloc(num_indices * array->elem);
// If memory is full fail gracefully
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
free(pointer);
exit(0);
}
// Allocate resources and instantiate Array
else {
array->array = pointer;
array->len = 0;
array->size = num_indices;
}
}
// --------------------------------------------------------------------------------
Array init_array(char *dtype, size_t num_indices, char *name) {
// Determine memory blocks based on data type
int size;
if (strcmp(dtype, "float") == 0) size = sizeof(float);
else if (strcmp(dtype, "int") == 0) size = sizeof(int);
else if (strcmp(dtype, "double") == 0) size = sizeof(double);
else if (strcmp(dtype, "char") == 0) size = sizeof(char);
else {
printf("Data type not correctly entered into init_array, exiting program!\n");
exit(0);
}
// Allocate indice size and call array_mem_alloc
Array array;
array.dtype = dtype;
array.elem = size;
array_mem_alloc(&array, num_indices);
array.name = name;
return array;
}
// --------------------------------------------------------------------------------
int append_array(Array *array, void *elements, size_t count) {
// Allocae more memory if necessary
if (array->len + count > array->size) {
size_t size = (array->len + count) * 2;
void *pointer = realloc(array->array, size * array->elem);
// If memory is full return operations
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
return 0;
}
// Allocate memory to variables and increment array size
array->array = pointer;
array->size = size;
}
// Append variables and increment the array length
memcpy((char *)array->array + array->len * array->elem, elements, count * array->elem);
array->len += count;
return 1;
}
// --------------------------------------------------------------------------------
void free_array(Array *array) {
// Free all memory in the array
free(array->array);
// Reset all variables in the struct
array->array = NULL;
array->size = 0;
array->len = 0;
array->elem = 0;
}
// --------------------------------------------------------------------------------
int int_array_val(Array *array, int indice) {
// Ensure array contains integers
printf("%s\n", array->dtype);
if (strcmp(array->dtype, "int") != 0) {
printf("Function can only return integer values, exiting function!\n");
exit(0);
}
// Cast value to an integer and return
int a = ((int *)array->array)[indice];
return a;
}
Array find_int_array_indices(Array *array, int integer) {
int number = 0;
int input;
for (int i = 0; i < array->len; i++) {
if (integer == int_array_val(array, i)) {
number++;
}
}
char dtype[7] = "int";
char name[9] = "indices";
Array indice_arr = init_array(dtype, number, name);
for (int i = 0; i < array->len; i++) {
input = i;
if (integer == int_array_val(array, i)) {
append_array(&indice_arr, &input, 1);
}
}
return indice_arr;
}
main.c
size_t indices = 10;
char name[6] = "array";
char dtype[7] = "int";
Array arr_test = init_array(dtype, indices, name);
int a[7] = {6, 1, 3, 6, 6, 4, 5};
append_array(&arr_test, a, 7);
Array p = find_int_array_indices(&arr_test, 6);
printf("%s\n", p.dtype); // This shows that p does contain dtype "int"
int d = int_array_val(&p, 0); // This fails in function, because it does not see dtype = "int"???
printf("%d\n", d);
In find_int_array_indices
char dtype[7] = "int";
char name[9] = "indices";
are both local variables, which are invalidated when the function returns. See: Dangling pointer and Lifetime.
init_array uses these values as if they had a lifetime to match its return value
Array array;
array.dtype = dtype;
array.elem = size;
array_mem_alloc(&array, num_indices);
array.name = name;
return array;
which, as a structure type, is a lifetime determined by the context of its caller (return is copy, after all).
find_int_array_indices completes the error when it returns indice_arr to main.
Some options:
Strictly use pointers to strings with static storage duration.
Change your structure definition to include space for these strings (or allocate it), and perform string copies.
Use an enumerated type instead.
Ditch this string-based, type limited paradigm all together by supporting all memory sizes generically (the naming feature remains an issue, though).
A rather long-winded continuation, to elaborate on using enumerated types:
The idea is to define a smaller set of acceptable values that your library works with, and making the user more aware of these values. As we can see, you have partially done that using strings but the implementation has some issues, as strings are generally clunky. Some problems with strings:
you have no control over the strings that users of your library use (this leads you to have to exit1 the program in the event the users enters something unexpected, which is easy to do),
you must account for their potentially large or excess memory consumption,
string comparison is O(N),
strings are generally unsafe in C, requiring more care than other basic constructs when handling them (assignment, comparison, storage).
So instead of using strings ("foo", "bar", "qux" in these examples), we use an enumerated type
enum OBJECT_TYPE {
OBJECT_FOO,
OBJECT_BAR,
OBJECT_QUX
};
which establishes the following:
it is more clear what the acceptable values are
some2 control over what users enter, via type hinting
comparison is O(1)
handling is the same as any integral type
The structure definition then looks like
typedef struct {
/* ... whatever members are needed for the structure */
size_t something_based_on_type;
enum OBJECT_TYPE type;
char debug_name[MAX_DEBUG_NAME];
} Object;
Nothing can really be done about the name member of your structure. If you want user defined nametags for things, then yes, as stated previously, you need to allocate space for them.
Our initialization function works similarly, but we can2 take advantage of some properties of integral types.
void object_init(Object *object, enum OBJECT_TYPE type, const char *debug_name) {
/* ... accept other arguments, whatever is needed to initialize */
size_t value_translations[] = { 42, 51, 99 };
object->type = type;
/* while neat, this is somewhat naive, see footnotes */
object->something_based_on_type = value_translations[type];
if (debug_name && strlen(debug_name) < MAX_DEBUG_NAME)
strcpy(object->debug_name, debug_name);
else
*object->debug_name = '\0';
}
Now we want to provide a function that works with our generic data of only type OBJECT_FOO (like your int_array_val). Again, the comparison is much easier to understand.
void object_print_foo(Object *o) {
if (OBJECT_FOO != o->type)
/* handle type mismatch */;
}
Although it would be better to provide a generic object_print function that again branches based on o->type.
A main function for completeness:
int main(void) {
Object a;
object_init(&a, OBJECT_QUX, "object_a");
object_print_foo(&a);
}
This is the general idea of using enumerated types.
With all that said, I think this is not really any better than just handling arbitrary data sizes, risks included. Something like
const void *array_get(Array *array, size_t index) {
if (index >= array->length)
return NULL;
return (char *) array->array + index * array->elem;
}
works, if the user respects the const contract, and uses the correct types (they would need to remember their typing with specifically typed getters too).
Generic data structures in C are a bit of a leap of faith no matter what.
1. So a note on exiting from library code: don't. As a library author, you have no reasonable right to cause user programs to terminate (unless requested, or the user invokes UB outside your control). Delegate upwards, return errors, and let the user exit the program on their own terms, as they may need to perform their own cleanups (or might carry on if the failure is non-critical).
2. C's enumeration type is rather weak. enum are actually just int, and users can enter plain integer values outside the specified ranges. This is akin to invoking undefined behavior from a library's point of view, but we may wish to protect the user anyway.
I am trying to use an array of pointers to a struct that has a pointer in it to another struct that is being used with an array of pointers.
I can write the code for a two single structs and it works. However, I am not sure how to deal with the introduction of the array of pointers.
Sample code:
typedef struct {
double vx;
} particle_t;
typedef struct {
int m;
int n;
particle_t *inparticles; // Pointer to particles inside grid
} grid_t;
particle_t *particles = (particle_t*) malloc( 3 * sizeof(particle_t) );
grid_t *grid = (grid_t*) malloc( 3 * sizeof(grid_t) ); // trying 3 pointers
if( particles==NULL || grid==NULL ){
puts("Unable to allocate memory");
exit(1);}
// fill the structure
grid[1].inparticles = particles[1]; // I am not sure how to link these
grid[2].inparticles = particles[2]; // these lines give incompatible types error
grid[3].inparticles = particles[3];
grid[1].m = 5;
grid[1].n = 3;
grid[1].inparticles -> vx = 15;
Thank you in advance!
Update:
I realized that what I should be doing is use the inparticles pointer to point to multiple particles in the same grid pointer? How I can change the code so I can be able to do that?
for example:
grid[0].inparticles[0] = particles[0];
grid[0].inparticles[1] = particles[1];
grid[0].inparticles[2] = particles[2];
declare it as an array somehow? would I need memory allocation for it as well?
Each member of particles has type particle_t. The inparticles member of grid_t has type particle_t *. So you want:
grid[1].inparticles = &particles[1];
grid[2].inparticles = &particles[2];
grid[3].inparticles = &particles[3];
Addressing your update, if you want to have inparticles point to various members of particles, you would need to change the inparticles to be a pointer-to-pointer:
typedef struct {
int m;
int n;
particle_t **inparticles;
} grid_t;
Then you would have to allocate space for an array of pointers, then assign each pointer:
grid[0].inparticles = malloc(3 * sizeof(particle_t *));
grid[0].inparticles[0] = &particles[0];
grid[0].inparticles[1] = &particles[1];
grid[0].inparticles[2] = &particles[2];
Issues
Design
I am trying to use an array of pointers to a struct that has a pointer in it to another struct that is being used with an array of pointers.
In other words, we must find a way to design "An array of pointers to a struct, which contains a pointer to another struct used as an array".
I will focus on this.
Array of pointers
However, I am not sure how to deal with the introduction of the array of pointers.
Well, we don't have any array of pointers in your code... you must create one first.
C pointers, arrays, structures and all their combinations have countless threads all over the internet which have been answered several times. I will show you a few basic examples so you can be up and running, just don't expect me to give you a whole lesson of pointers.
Solutions
Design
Here is the code (I changed some variable names to make it more readable):
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
double value;
}Particle;
typedef struct
{
int width;
int height;
Particle *particles;
}Grid;
Grid *createGrid(int width, int height)
{
Grid *result = malloc(sizeof(Grid));
if (result == NULL)
{
printf("Error while allocating memory for the grid structure!\n");
exit(1);
}else
{
result->width = width;
result->height = height;
result->particles = malloc(sizeof(Particle) * width*height);
}
return result;
}
void destroyGrid(Grid *grid)
{
free(grid->particles);
free(grid);
}
int main()
{
Grid *grids[3];
for (int i = 0; i < 3; i++)
grids[i] = createGrid(5, 3);
/* Assign, modify, read or copy values from the array of pointers here */
for (int i = 0; i < 3; i++)
destroyGrid(grids[i]);
return 0;
}
As you can see, I introduced 2 functions to make your life easier: createGrid and destroyGrid.
The first one will need you to specify 2 arguments: the width and height (m and n in your code) of a grid. The function is then going to allocate memory and return a pointer to the grid it just created.
The second one will need you to specify 1 argument: a pointer to a grid. The function is then going to free all the memory the first function allocated, avoiding any memory leaks.
I've also added an array of pointers in the main function: grids. This, in combination with the usage of the functions described above (all in the main function), solves the first issue.
The final design can be read as follows:
"We have an array of pointers to a struct (grids), which contains a pointer to another struct (particles) which should be used as an array".
Array of pointers
You may be wondering now: "OK, so how am I supposed to use this array-of-pointers-to-a-structure-confusing-stuff?" As I said before, I will show you a practical example only.
Lets assume you want to set the value of the third particle of the first grid to 2.7182: (you should insert this code in the place I commented as /* Assign, modify, read or copy values from the array of pointers here */)
grids[0]->particles[2].value = 2.7182;
And this can be read, from left to right, as: "From the array of pointers grids, get the element with index 0 (the first pointer to a Grid structure). Access its structure member particles, which is a pointer. Treat that pointer as an array and get the element with index 2 (the third Particle structure). Access its member value and assign to it the value 2.7182"
You could then do something like copy one particle to another:
grids[1]->particles[1] = grids[0]->particles[2];
Here are some links to better understand pointers, arrays and structs. Practice and experimentation is the best way to deal with them:
https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Pointers
https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Arrays
https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Structures
Update
I realized that what I should be doing is use the inparticles pointer to point to multiple particles in the same grid pointer
I need to use a separate array of pointers to particles. The array inside the grid structure is only to point to a subset of particles.
Objective: "Use the inparticles pointer to point to a subset of multiple (sequential or non-sequential?) particles (which are being managed somewhere else)".
If you want the sequential solution you could use a pointer, representing a pointer to the base address (or offset, if you want only a subset) of an array (this is, a pointer to an array). This has the advantage of not needing you to allocate extra memory for every single pointer (since only the base address is necessary), but it has the disadvantage that you can only access particles that are next to each other.
Example:
typedef struct
{
int width;
int height;
Particle *subparticles; //Represents a pointer to an array subset
}Grid;
/*...*/
grids[0]->subparticles = &particles[0];
grids[1]->subparticles = &particles[1];
printf("%f equals %f", grids[0]->subparticles[1].value, grids[1]->subparticles[0].value);
/*...*/
However, If you want the non-sequential solution, you could use a double pointer (representing an array of pointers) while having to manually allocate memory for the array. This provides you with more flexibility, but comes at the price of memory allocation overhead.
typedef struct
{
/*...other members...*/
Particle **subparticles;
}Grid;
Grid *createGrid(int subparticlesCount)
{
Grid *result = malloc(sizeof(Grid));
if (result == NULL)
{
printf("Error while allocating memory for the grid structure!\n");
exit(1);
}else
{
result->subparticles = malloc(sizeof(Particle *) * subparticlesCount);
}
return result;
}
/*...*/
grids[0]->subparticles[0] = &particles[1];
grids[0]->subparticles[1] = &particles[5];
grids[0]->subparticles[2] = &particles[3];
grids[1]->subparticles[0] = &particles[3];
printf("%f equals %f", grids[0]->subparticles[2]->value, grids[1]->subparticles[0]->value);
/*...*/
Instead of a field which is a pointer (to some array), if that field is the last of its struct, you could make it a flexible array member. So declare
typedef struct {
int m;
int n;
unsigned count;
particle_t inparticle_arr[]; // flexible array of count elements
} grid_t;
See this answer for an example and details, and a C standard (like n1570 §6.7.2.1) or this C reference.
In some cases, avoiding pointers and indirection may slightly speedup your code (because of the CPU cache). Flexible array members also avoid an extra free for that internal flexible array.
For debugging and avoiding buffer overflows, compile your C code with GCC invoked as gcc -Wall -Wextra -g and use also valgrind (or the address sanitizer).
Based on the question and subsequent comments, what I understood is that you want to create a grid which should contain a pointer to an array of pointers (i.e multiple pointers) in which each pointer points to struct of type particle_t.
On the basis of this understanding, I have modified your original code and have provided appropriate comments in the code itself wherever necessary. However, if I have misinterpreted your question then let me know, I will update the answer accordingly.
#include<stdio.h>
#include<stdlib.h>
typedef struct {
double vx;
} particle_t;
typedef struct {
int m;
int n;
particle_t **inparticles; // inparticles is a pointer to (array of
// pointers to inparticle)
int size; // max number of particles in the grid
} grid_t;
grid_t *new_grid(int size) { // A helper function to create grid
grid_t *grid = (grid_t*)malloc(sizeof(grid_t));
grid->inparticles = (particle_t**)malloc(sizeof(particle_t*));
if(grid == NULL || grid->inparticles == NULL) return NULL;
grid->size = size;
for(int i=0;i<size;++i) {
grid->inparticles[i] = (particle_t*)malloc(sizeof(particle_t));
if(grid->inparticles[i] == NULL) {
return NULL;
}
}
return grid;
}
int main() {
particle_t *particles = (particle_t*)malloc( 3 * sizeof(particle_t) );
//create a new grid which can contain multiple particles --- Use a for
//loop for creating multiple grids
grid_t *grid = new_grid(3);
if( particles==NULL || grid==NULL ){
puts("Unable to allocate memory");
exit(1);
}
grid->inparticles[0] = &particles[0];
grid->inparticles[1] = &particles[1];
grid->inparticles[2] = &particles[2];
return 0;
}
When things get complicated, divide and conquer is the best approach.
Create an array of structs of type particle_t on the heap:
particle_t* partAddr = malloc(sizeof(particle_t) * numParticles);
Create an array of structs of type grid_t on the heap:
grid_t* gridAddr = malloc(sizeof(grid_t) * numGrids);
Make one element of the array of type grid_t to point to an allocated element of type particle_t:
gridAddr[n].inparticles = partAddr;
Assign a value to the vx field of the first element of the array of the first element of the grid:
grid[0].inparticles[0].vx= 3;
Everything together (where the number of particles can vary):
// Define the size of each array of particles
#define ELEMENTS_ARRAY_PARTICLE_A 5
#define ELEMENTS_ARRAY_PARTICLE_B 2
#define ELEMENTS_ARRAY_PARTICLE_C 7
// Create indexes and size to avoid out of boundaries accesses
enum GRID_PARTICLES {
ARRAY_PARTICLE_0 = 0,
ARRAY_PARTICLE_1,
ARRAY_PARTICLE_2,
GRID_SIZE
};
typedef struct {
double vx;
} particle_t;
typedef struct {
particle_t *inparticles;
} grid_t;
particle_t* allocateArrayOfParticles(int numParticles) {
particle_t* partAddr = malloc(sizeof(particle_t) * numParticles);
if(partAddr == NULL){
// trigger an error
}
return partAddr;
}
void deallocateArrayOfParticles(particle_t *partAddr) {
free(partAddr);
}
grid_t* allocateGridOfParticles(int numGrids) {
grid_t* gridAddr = malloc(sizeof(grid_t) * numGrids);
if(gridAddr == NULL) {
// trigger an error
}
return gridAddr;
}
void deallocateGridOfParticles(grid_t *gridAddr) {
free(gridAddr);
}
int main(void) {
grid_t *grid = allocateGridOfParticles(GRID_SIZE);
particle_t *partA = allocateArrayOfParticles(ELEMENTS_ARRAY_PARTICLE_A);
particle_t *partB = allocateArrayOfParticles(ELEMENTS_ARRAY_PARTICLE_B);
particle_t *partC = allocateArrayOfParticles(ELEMENTS_ARRAY_PARTICLE_C);
grid[ARRAY_PARTICLE_0].inparticles = partA;
grid[ARRAY_PARTICLE_1].inparticles = partB;
grid[ARRAY_PARTICLE_2].inparticles = partC;
deallocateArrayOfParticles(partA);
deallocateArrayOfParticles(partB);
deallocateArrayOfParticles(partC);
deallocateGridOfParticles(grid);
}
I want to use a struct to contain some data and passing them between different functions in my program,this struct has to contain a dynamic 2D array (i need a matrix) the dimensions change depending on program arguments.
So this is my struct :
struct mystruct {
int **my2darray;
}
I have a function that read numbers from a file and has to assign each of them to a cell of the struct array.
I tried doing this :
FILE *fp = fopen(filename, "r");
int rows;
int columns;
struct mystruct *result = malloc(sizeof(struct mystruct));
result->my2darray = malloc(sizeof(int)*rows);
int tmp[rows][columns];
for(int i = 0;i<rows;i++) {
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &tmp[i][j]);
}
result->my2darray[i]=malloc(sizeof(int)*columns);
memcpy(result->my2darray[i],tmp[i],sizeof(tmp[i]));
}
But this is giving me a strange result : all the rows are correctly stored except for the first.
(I'm sure that the problem is not in the scanning of file).
While if i change the fourth line of code in this :
result->my2darray = malloc(sizeof(int)*(rows+1));
it works fine.
Now my question is why this happens?
Here's an answer using some "new" features of the language: flexible array members and pointers to VLA.
First of all, please check Correctly allocating multi-dimensional arrays. You'll want a 2D array, not some look-up table.
To allocate such a true 2D array, you can utilize flexible array members:
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
It will be allocated as a true array, although "mangled" into a single dimension:
size_t x = 2;
size_t y = 3;
array2d_t* arr2d = malloc( sizeof *arr2d + sizeof(int[x][y]) );
Because the problem with flexible array members is that they can neither be VLA nor 2-dimensional. And although casting it to another integer array type is safe (in regards of aliasing and alignment), the syntax is quite evil:
int(*ptr)[y] = (int(*)[y]) arr2d->flex; // bleh!
It would be possible hide all this evil syntax behind a macro:
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
Read as: if arr2d is a of type array2d_t* then access that pointer to get the flex member, then cast it to an array pointer of appropriate type.
Full example:
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
int main (void)
{
size_t x = 2;
size_t y = 3;
array2d_t* arr = malloc( sizeof *arr + sizeof(int[x][y]) );
arr->x = x;
arr->y = y;
for(size_t i=0; i<arr->x; i++)
{
for(size_t j=0; j<arr->y; j++)
{
get_array(arr)[i][j] = i+j;
printf("%d ", get_array(arr)[i][j]);
}
printf("\n");
}
free(arr);
return 0;
}
Advantages over pointer-to-pointer:
An actual 2D array that can be allocated/freed with a single function call, and can be passed to functions like memcpy.
For example if you have two array2d_t* pointing at allocated memory, you can copy all the contents with a single memcpy call, without needing to access individual members.
No extra clutter in the struct, just the array.
No cache misses upon array access due to the memory being segmented all over the heap.
The code above never sets rows and columns, so the code has undefined behavior from reading those values.
Assuming you set those values properly, this isn't allocating the proper amount of memory:
result->my2darray = malloc(sizeof(int)*rows);
You're actually allocating space for an array of int instead of an array of int *. If the latter is larger (and it most likely is) then you haven't allocated enough space for the array and you again invoke undefined behavior by writing past the end of allocated memory.
You can allocate the proper amount of space like this:
result->my2darray = malloc(sizeof(int *)*rows);
Or even better, as this doesn't depend on the actual type:
result->my2darray = malloc(sizeof(*result->my2darray)*rows);
Also, there's no need to create a temporary array to read values into. Just read them directly into my2darray:
for(int i = 0;i<rows;i++) {
result->my2darray[i]=malloc(sizeof(int)*columns);
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &result->my2darray[i][j]);
}
}
In your provided code example, the variables rows and columns have not been initialized before use, so they can contain anything, but are likely to be equal to 0. Either way, as written, the results will always be unpredictable.
When a 2D array is needed in C, it is useful to encapsulate the memory allocation, and freeing of memory into functions to simplify the task, and improve readability. For example, in your code the following line will create an array of 5 pointers, each pointing to 20 int storage locations: (creating 100 index addressable int locations.)
int main(void)
{
struct mystruct result = {0};
result.my2darray = Create2D(5, 20);
if(result.my2darray)
{
// use result.my2darray
result.my2darray[0][3] = 20;// for simple example, but more likely in a read loop
// then free result.my2darray
free2D(result.my2darray, 5);
}
return 0;
}
Using the following two functions:
int ** Create2D(int c, int r)
{
int **arr;
int y;
arr = calloc(c, sizeof(int *)); //create c pointers (columns)
for(y=0;y<c;y++)
{
arr[y] = calloc(r, sizeof(int)); //create r int locations for each pointer (rows)
}
return arr;
}
void free2D(int **arr, int c)
{
int i;
if(!arr) return;
for(i=0;i<c;i++)
{
if(arr[i])
{
free(arr[i]);
arr[i] = NULL;
}
}
free(arr);
arr = NULL;
}
Keep in mind that what you have created using this technique is actually 5 different pointer locations each pointing to a set of 20 int locations. This is what facilitates the use of array like indexing, i.e. we can say result.my2darray[1][3] represents the second column, forth row element of a 5X20 array, when it is not really an array at all.
int some_array[5][20] = {0};//init all elements to zero
Is what is commonly referred to in C an int array, also allowing access to each element via indexing. In actuality (Even though commonly referred to as an array.) it is not an array. The location of elements in this variable are stored in one contiguous location in memory.
|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0... (~ 82 more)
But C maintains the locations such that they are all indexable as an 2D array.
Good morning!
I must handle a struct array (global variable) that simulates a list. In practice, every time I call a method, I have to increase the size of the array 1 and insert it into the new struct.
Since the array size is static, my idea is to use pointers like this:
The struct array is declared as a pointer to a second struct array.
Each time I call the increaseSize () method, the content of the old array is copied to a new n + 1 array.
The global array pointer is updated to point to a new array
In theory, the solution seems easy ... but I'm a noob of c. Where is that wrong?
struct task {
char title[50];
int execution;
int priority;
};
struct task tasks = *p;
int main() {
//he will call the increaseSize() somewhere...
}
void increaseSize(){
int dimension = (sizeof(*p) / sizeof(struct task));
struct task newTasks[dimension+1];
for(int i=0; i<dimension; i++){
newTasks[i] = *(p+i);
}
free(&p);
p = newTasks;
}
You mix up quite a lot here!
int dimension = (sizeof(*p) / sizeof(struct task));
p is a pointer, *p points to a struct task, so sizeof(*p) will be equal to sizeof(struct task), and dimension always will be 1...
You cannot use sizeof in this situation. You will have to store the size (number of elements) in a separate variable.
struct task newTasks[dimension+1];
This will create a new array, yes – but with scope local to the current function (so normally, it is allocated on the stack). This means that the array will be cleaned up again as soon as you leave your function.
What you need is creating the array on the heap. You need to use malloc function for (or calloc or realloc).
Additionally, I recomment not increasing the array by 1, but rather duplicating its size. You need to store the number of elements contained in then, too, though.
Putting all together:
struct task* p;
size_t count;
size_t capacity;
void initialize()
{
count = 0;
capacity = 16;
p = (struct task*) malloc(capacity * sizeof(struct task));
if(!p)
// malloc failed, appropriate error handling!
}
void increase()
{
size_t c = capacity * 2;
// realloc is very convenient here:
// if allocation is successful, it copies the old values
// to the new location and frees the old memory, so nothing
// so nothing to worry about except for allocation failure
struct task* pp = realloc(p, c * sizeof(struct task));
if(pp)
{
p = pp;
capacity = c;
}
// else: apprpriate error handling
}
Finally, as completion:
void push_back(struct task t)
{
if(count == capacity)
increase();
p[count++] = t;
}
Removing elements is left to you – you'd have to copy the subsequent elements all to one position less and then decrease count.
I'm trying to use dynamic array of a structure containning dynamic array.
The allocation is done in the function build_resuts and the memory is freed in the function free_data.
Am I doing this correctly ?
typedef struct InputResultsLine
{
long registered;
long *candidates;
} InputResultsLine;
void func()
{
InputResultsLine *data, totals;
int nbPollingPlaces = 10;
build_results(&data, &totals, 5, nbPollingPlaces);
free_data(&data, &totals, nbPollingPlaces);
}
void build_results(InputResultsLine **data, InputResultsLine *totals, int nbCandidates, int nbPollingPlaces)
{
int i;
InputResultsLine *ptrCurrentLine;
totals->candidates = (long*) malloc(nbCandidates * sizeof(long));
*data = (InputResultsLine*) malloc(nbPollingPlaces * sizeof(InputResultsLine));
for(i = 0; i < nbPollingPlaces; i++)
{
ptrCurrentLine = &((*data)[i]);
ptrCurrentLine->candidates = (long*) malloc(nbCandidates * sizeof(long));
// [...]
}
}
void free_data(InputResultsLine **data, InputResultsLine *totals, int nbPollingPlaces)
{
int i;
for(i = 0; i < nbPollingPlaces; i++)
{
free(((*data)[i]).candidates);
}
free(totals->candidates);
free(*data);
}
I saw samples where the allocation was like :
*data = (InputResultsLine*) malloc(nbPollingPlaces * (sizeof(InputResultsLine) + nbCandidates * sizeof(long)));
So i'm not sure how I should do and why :
(BTW, in C you don't need to cast the return value of malloc(): If it doesn't compile without a cast, you've made a mistake)
The code you find weird involves allocating all arrays in a single buffer: This allows for better "memory locality" (i.e. related things being together in memory) at the price of not being able to modify arrays individually: It's good for performance but only useful for data that is initialized once and does not change over time (or at least, whose size does not change over time).
It also allows you to free the whole thing with only one call to free() and makes error handling much simpler (since you don't have to check that all malloc() calls in a loop succeed, and if not, free all calls that had succeeded so far and not others...)