dynamically allocate 2d array of structs in C - arrays

(corrected the code after a few good comments pointing out some mistakes in the previous version of the code)
If I'm right, the best way to dynamically allocate a 2D array of structs in C is the following:
struct xx(*array2d)[y] = malloc(sizeof(struct xx[x][y]));
Does it make any difference whether I store the structs in the array or store pointers to them?
I was also wondering if I may simply deallocate the allocated memory in the following way:
void free2d(int x, int y, struct xx array2d[x][y]) {
free(array2d);
}

Identifiers in C cannot begin with numbers so 2darray won't work.
Formally, the most correct way to allocated a 2D array dynamically is:
struct xx (*array)[x][y] = malloc(sizeof(struct xx[x][y]));
However that makes accessing the array cumbersome, because we would have to de-reference the array pointer first:
(*array)[i][j]
A common trick to avoid this is to have the array pointer not point at the "whole" 2D array, but to the first item. Which would be a struct xx [y] array in this case.
So we can use a pointer to the first element but still allocate the correct amount:
struct xx (*array)[y] = malloc(sizeof(struct xx[x][y]));
And now we can use this as
array[i][j]
In either of the two examples above, you free it with a single free(array) call.

The allocation code is a bit incorrect.
variable name cannot start with a digit, thus identifier 2darray is illegal. Use array2d instead
memory allocation code look almost correct. Note that array2d would be a pointer to array of x elements of type struct xx. Thus the correct allocation code swap order of x and y in sizeof expression.
struct xx (*array2d)[x] = malloc(sizeof(struct xx[y][x]));
If you want x be the first dimensions use:
struct xx (*array2d)[y] = malloc(sizeof(struct xx[x][y]));
Personally I prefer to use the following pattern because it is less error prone:
struct xx (*array2d)[x] = calloc(y, sizeof *array2d);
Passing to function. It is simple, just pass array dimensions as arguments and then the array itself.
void foo(int x, int y, struct xx array2d[static x][y]) {
Note that parameter array2d is actually a pointer to array. The "static extent" tells the compiler that at least x elements pointer by the pointer are valid. It is very useful for documentation. Moreover static makes the declaration visually distinct from a declaration of an array.
Deallocation. The free2d function could be used if it followed the pattern from point 2. However I recommend simply using free(array2d);

I would use objects instead of types.
struct xx(*array2d)[cols] = malloc(rows *sizeof(*array2D));
To deallocate you do not need sizes only void pointer to your array
void free2d(void *array2d) {
free(array2d);
}
or simple use free with your pointer to the array.

Related

How are C structs with arrays returned?

Suppose we have:
typedef struct {
uint8_t someVal;
} Entry
typedef struct {
Entry grid[3][3];
} Matrix
//Make a 3x3 matrix of all 0s
Matrix emptyMatrix(void) {
Entry zero = {.value = 0}
Matrix matrix;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++) {
//Shallow copy empty struct
matrix.grid[i][j] = zero;
}
return matrix;
}
Matrix myMatrix = emptyMatrix();
I understand that in C we're allowed to return a struct from a function so this works and I've tested it. However, it's unclear to me HOW the assignment works.
Does the compiler allocate the memory for myMatrix then copy each Entry element of the array in the Matrix struct returned by emptyMatrix()?
I guess it would also be helpful to know the memory map of Matrix - I assumed that since grid is an array that Matrix's memory would contain pointers. However, it apparently stores the value. If this is the case, my guess for how the assignment works makes much more sense to me.
Edit: It seems like people are answering the question incompletely. I want to know whether my guess of how the assignment works is correct.
Each instance of Matrix will contain a 3x3 array of Entry. When you assign one instance of Matrix to another, the contents of the source matrix will be copied to the destination matrix.
Arrays are not pointers. Array expressions will "decay" to pointers if the expression is not the operand of the sizeof or unary & operators, or is not a string literal used to initialize a character array in a declaration.
For example, if you had a function call like
printMatrix( myMatrix.grid );
the expression myMatrix.grid has type "3-element array of 3-element array of Entry"; since it's not the operand of the sizeof or unary & operator, it "decays" to an expression of type "pointer to 3-element array of Entry" (Entry (*)[3]) and the value of the expression is the address of the first element of grid (which will also be the address of the whole Matrix instance).
The ABI for each environment defines how structures are passed and returned by value. A common choice is this:
small structures, up to the size of 2 or 4 registers are returned in registers.
for larger objects, the caller allocates space on its stack frame for the return value and passes a pointer to the function. When returning, the function copies whatever object is being returned into the space to which it received a pointer for the return value. That's it. This simple method allows for recursive calls.
the optimizer tries to minimize the amount of copying, especially if it can expand the function inline or if the returned value is stored into an object, as opposed to discarded or passed by value to another function.
It does not matter if the structure has one or more member arrays. The same method applies to unions as well.
Identifiers bound to arrays may be interpreted as pointers, but that doesn't mean that the array variables are pointers.
The storage for the array is part of the memory layout of the struct itself. The same way as arrays declared on the stack are on the stack itself.
You can test this by yourself by checking sizeof(Matrix).
So in short:
Does the compiler allocate the memory for myMatrix then copy each Entry element of the array in the Matrix struct returned by emptyMatrix()?
Yes
Matrix is a data type struct struct {Entry grid[3][3];}. For every object of the type Metrix memory of size Entry grid[3][3] will be allocated.
Function emptyMatrix is returning an object of type Matrix and the object will be returned by value just like any other object.

Differences when using ** in C

I started learning C recently, and I'm having a problem understanding pointer syntax, for example when I write the following line:
int ** arr = NULL;
How can I know if:
arr is a pointer to a pointer of an integer
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
Isn't it all the same with int ** ?
Another question for the same problem:
If I have a function that receives char ** s as a parameter, I want to refer to it as a pointer to an array of strings, meaning a pointer to an array of pointers to an array of chars, but is it also a pointer to a pointer to a char?
Isn't it all the same with int **?
You've just discovered what may be considered a flaw in the type system. Every option you specified can be true. It's essentially derived from a flat view of a programs memory, where a single address can be used to reference various logical memory layouts.
The way C programmers have been dealing with this since C's inception, is by putting a convention in place. Such as demanding size parameter(s) for functions that accept such pointers, and documenting their assumptions about the memory layout. Or demanding that arrays be terminated with a special value, thus allowing "jagged" buffers of pointers to buffers.
I feel a certain amount of clarification is in order. As you'd see when consulting the other very good answers here, arrays are most definitely not pointers. They do however decay into ones in enough contexts to warrant a decades long error in teaching about them (but I digress).
What I originally wrote refers to code as follows:
void func(int **p_buff)
{
}
//...
int a = 0, *pa = &a;
func(&pa);
//...
int a[3][10];
int *a_pts[3] = { a[0], a[1], a[2] };
func(a_pts);
//...
int **a = malloc(10 * sizeof *a);
for(int i = 0; i < 10; ++i)
a[i] = malloc(i * sizeof *a[i]);
func(a);
Assume func and each code snippet is compiled in a separate translation unit. Each example (barring any typos by me) is valid C. The arrays will decay into a "pointer-to-a-pointer" when passed as arguments. How is the definition of func to know what exactly it was passed from the type of its parameter alone!? The answer is that it cannot. The static type of p_buff is int**, but it still allows func to indirectly access (parts of) objects with vastly different effective types.
The declaration int **arr says: "declare arr as a pointer to a pointer to an integer". It (if valid) points to a single pointer that points (if valid) to a single integer object. As it is possible to use pointer arithmetic with either level of indirection (i.e. *arr is the same as arr[0] and **arr is the same as arr[0][0]) , the object can be used for accessing any of the 3 from your question (that is, for second, access an array of pointers to integers, and for third, access an array of pointers to first elements of integer arrays), provided that the pointers point to the first elements of the arrays...
Yet, arr is still declared as a pointer to a single pointer to a single integer object. It is also possible to declare a pointer to an array of defined dimensions. Here a is declared as a pointer to 10-element array of pointers to arrays of 10 integers:
cdecl> declare a as pointer to array 10 of pointer to array 10 of int;
int (*(*a)[10])[10]
In practice array pointers are most used for passing in multidimensional arrays of constant dimensions into functions, and for passing in variable-length arrays. The syntax to declare a variable as a pointer to an array is seldom seen, as whenever they're passed into a function, it is somewhat easier to use parameters of type "array of undefined size" instead, so instead of declaring
void func(int (*a)[10]);
one could use
void func(int a[][10])
to pass in a a multidimensional array of arrays of 10 integers. Alternatively, a typedef can be used to lessen the headache.
How can I know if :
arr is a pointer to a pointer of an integer
It is always a pointer to pointer to integer.
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
It can never be that. A pointer to an array of pointers to integers would be declared like this:
int* (*arr)[n]
It sounds as if you have been tricked to use int** by poor teachers/books/tutorials. It is almost always incorrect practice, as explained here and here and (
with detailed explanation about array pointers) here.
EDIT
Finally got around to writing a detailed post explaining what arrays are, what look-up tables are, why the latter are bad and what you should use instead: Correctly allocating multi-dimensional arrays.
Having solely the declaration of the variable, you cannot distinguish the three cases. One can still discuss if one should not use something like int *x[10] to express an array of 10 pointers to ints or something else; but int **x can - due to pointer arithmetics, be used in the three different ways, each way assuming a different memory layout with the (good) chance to make the wrong assumption.
Consider the following example, where an int ** is used in three different ways, i.e. p2p2i_v1 as a pointer to a pointer to a (single) int, p2p2i_v2 as a pointer to an array of pointers to int, and p2p2i_v3 as a pointer to a pointer to an array of ints. Note that you cannot distinguish these three meanings solely by the type, which is int** for all three. But with different initialisations, accessing each of them in the wrong way yields something unpredictable, except accessing the very first elements:
int i1=1,i2=2,i3=3,i4=4;
int *p2i = &i1;
int **p2p2i_v1 = &p2i; // pointer to a pointer to a single int
int *arrayOfp2i[4] = { &i1, &i2, &i3, &i4 };
int **p2p2i_v2 = arrayOfp2i; // pointer to an array of pointers to int
int arrayOfI[4] = { 5,6,7,8 };
int *p2arrayOfi = arrayOfI;
int **p2p2i_v3 = &p2arrayOfi; // pointer to a pointer to an array of ints
// assuming a pointer to a pointer to a single int:
int derefi1_v1 = *p2p2i_v1[0]; // correct; yields 1
int derefi1_v2 = *p2p2i_v2[0]; // correct; yields 1
int derefi1_v3 = *p2p2i_v3[0]; // correct; yields 5
// assuming a pointer to an array of pointers to int's
int derefi1_v1_at1 = *p2p2i_v1[1]; // incorrect, yields ? or seg fault
int derefi1_v2_at1 = *p2p2i_v2[1]; // correct; yields 2
int derefi1_v3_at1 = *p2p2i_v3[1]; // incorrect, yields ? or seg fault
// assuming a pointer to an array of pointers to an array of int's
int derefarray_at1_v1 = (*p2p2i_v1)[1]; // incorrect; yields ? or seg fault;
int derefarray_at1_v2 = (*p2p2i_v2)[1]; // incorrect; yields ? or seg fault;
int derefarray_at1_v3 = (*p2p2i_v3)[1]; // correct; yields 6;
How can I know if :
arr is a pointer to a pointer of an integer
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
You cannot. It can be any of those. What it ends up being depends on how you allocate / use it.
So if you write code using these, document what you're doing with them, pass size parameters to the functions using them, and generally be sure about what you allocated before using it.
Pointers do not keep the information whether they point to a single object or an object that is an element of an array. Moreover for the pointer arithmetic single objects are considered like arrays consisting from one element.
Consider these declarations
int a;
int a1[1];
int a2[10];
int *p;
p = &a;
//...
p = a1;
//...
p = a2;
In this example the pointer p deals with addresses. It does not know whether the address it stores points to a single object like a or to the first element of the array a1 that has only one element or to the first element of the array a2 that has ten elements.
The type of
int ** arr;
only have one valid interpretation. It is:
arr is a pointer to a pointer to an integer
If you have no more information than the declaration above, that is all you can know about it, i.e. if arr is probably initialized, it points to another pointer, which - if probably initialized - points to an integer.
Assuming proper initialization, the only guaranteed valid way to use it is:
**arr = 42;
int a = **arr;
However, C allows you to use it in multiple ways.
• arr can be used as a pointer to a pointer to an integer (i.e. the basic case)
int a = **arr;
• arr can be used as a pointer to a pointer to an an array of integer
int a = (*arr)[4];
• arr can be used as a pointer to an array of pointers to integers
int a = *(arr[4]);
• arr can be used as a pointer to an array of pointers to arrays of integers
int a = arr[4][4];
In the last three cases it may look as if you have an array. However, the type is not an array. The type is always just a pointer to a pointer to an integer - the dereferencing is pointer arithmetic. It is nothing like a 2D array.
To know which is valid for the program at hand, you need to look at the code initializing arr.
Update
For the updated part of the question:
If you have:
void foo(char** x) { .... };
the only thing that you know for sure is that **x will give a char and *x will give you a char pointer (in both cases proper initialization of x is assumed).
If you want to use x in another way, e.g. x[2] to get the third char pointer, it requires that the caller has initialized x so that it points to a memory area that has at least 3 consecutive char pointers. This can be described as a contract for calling foo.
C syntax is logical. As an asterisk before the identifier in the declaration means pointer to the type of the variable, two asterisks mean pointer to a pointer to the type of the variable.
In this case arr is a pointer to a pointer to integer.
There are several usages of double pointers. For instance you could represent a matrix with a pointer to a vector of pointers. Each pointer in this vector points to the row of the matrix itself.
One can also create a two dimensional array using it,like this
int **arr=(int**)malloc(row*(sizeof(int*)));
for(i=0;i<row;i++) {
*(arr+i)=(int*)malloc(sizeof(int)*col); //You can use this also. Meaning of both is same. //
arr[i]=(int*)malloc(sizeof(int)*col); }
There is one trick when using pointers, read it from right hand side to the left hand side:
int** arr = NULL;
What do you get: arr, *, *, int, so array is a pointer to a pointer to an integer.
And int **arr; is the same as int** arr;.
int ** arr = NULL;
It's tell the compiler, arr is a double pointer of an integer and assigned NULL value.
There are already good answers here, but I want to mention my "goto" site for complicated declarations: http://cdecl.org/
Visit the site, paste your declaration and it will translate it to English.
For int ** arr;, it says declare arr as pointer to pointer to int.
The site also shows examples. Test yourself on them, then hover your cursor to see the answer.
(double (^)(int , long long ))foo
cast foo into block(int, long long) returning double
int (*(*foo)(void ))[3]
declare foo as pointer to function (void) returning pointer to array 3 of int
It will also translate English into C declarations, which is prety neat - if you get the description correct.

Pointer to a first structure in an array of structures?

I have a function that is supposed to be creating structures and storing them in an array of structures.
Lets say this is my structure:
struct str {
...
};
The function takes a parameter that looks like this:
struct str **ptr
Which is a pointer to a pointer that points to a structure if I get it right and I am supposed to set this parameter to be pointing to the first element of the array of structures which will be the first structure in that array.
So, if the parameter looks like this, that means that instead of having just an array of structures, I have an array of pointers that point to that structure, right?
Now I have declared the array of pointers to structures like this:
struct str *structures[20];
because I am expecting to have 20 (pointers to )structures store there.
Then I have a loop that is allocating memory for the structures and is storing them in the array like this:
struct str *structure;
structure = malloc(sizeof(struct str));
Then I fill in the parameters of the structure I want like this:
structure->a = 1; structure->b = 2; .........
And I store it in the array like this:
structures[n] = structure;
And I make sure it is stored in the array at the position where I wanted it to be by printing a parameter from the structure each loop like this:
printf("%d\n", structures[7]->a);
My question is, how do I set the parameter of the function to be pointing to the first pointer to a structure in that array?
And did I get it right?
Also, the parameter needs to be taken from main.
And I need to work with these (pointers to)structures of the array outside this one function as well.
What will the parameter look like?
struct str *pointer; ?
Also, wouldn't it be possible to just point the pointer to the array itself and it should automatically be pointing to the first element in it?
So that I could then reference the nth member of the array via the pointer since I need to work with all of them later on?
I have looked at this thread, but I'm still a bit confused so I'd appreciate any feedback.
Reading through this, I notice a few inconsistencies in your post:
Why create an array of pointers to your struct as opposed to a simple array of structs? That is, let's say you have this declaration for your struct:
struct myStruct {
int x;
int y;
};
If you want to create an array of those structs just do:
//dynamic
struct myStruct* myArray = malloc(20*sizeof(struct myStruct));
//static
struct myStruct* myArray[20];
Note that both of these return a pointer to the first element of the array (which is of type struct myStruct). Your array is an array of struct myStruct elements, not an array of struct myStruct*.
An array of struct myStruct elements with size 20 is, for practical purposes, nothing more than contiguous memory big enough to hold 20 struct myStruct elements and represented by the pointer to the first element. Since the memory is contiguous, you can access the 'nth' element of your array by myArray[0] or *(myArray+n) (the latter is possible because an "array" is nothing more than a pointer to the first element of contiguous memory... so "adding" 1 to a pointer of a given type gives you the memory address of the next element... which you deference using the * operator to get the element itself).
It'll be much easier (not to mention much faster) to allocate memory for your array of structs once rather than creating an array of pointers to your structs. And then modify them in place.
So a function that takes in the array and increments that 5th and 6th elements might look like:
void modifyStructs (struct myStruct* myArray)
{
//modify the fifth struct:
++myArray[4].x;
//modify the sixth struct:
++myArray[5].x;
}
The few times you'll want an array of pointers are when:
Creating a multidimensional array. Even then, this is really bad for cache performance... it's better to create a 1D array and define a macro for how to access the elements. BLAS/LAPACK do this.
Creating an array where some elements should be NULL and you're not using structs. If you're using structs, it's much better to just define a field to identify whether your struct has been populated yet and use a simple array of structs.
Creating an array to access a huge number of items but you don't want to allocate all that memory yet. Here, you don't really have a choice.

How to turn an int pointer to an array

So this was presented in our class (I was absent that time):
typedef struct{
int *items;
int size;
int max;
}list;
and a list was passed to a function:
void append(list *l, int x){
if(l->size==l->max){
expand(l);
}
l->items[l->size++] = x;
}
My question is, how can an int pointer have an index? I thought indexes were used on arrays? Can that be done?
I'm new to C. So yeah.
A pointer can point at either 1 or n elements of its type. There is no way of telling which it is just from the declaration. We can assume that items is the address of the first element of an array. Since arrays store their elements in sequence, when you index the pointer, you really apply an offset from the first address. Hence, you index into the array that the pointer points at.
int values[5]; // Simple array.
int* p = values; // p points to the first element of the array values.
p[2] = 34; // Equivalent to values[2] = 34;
A pointer is simply the address to the memory space allocated for your object/array/int.
You can have a pointer to anything memory-related in C. You just say, here is my int, here is my array, etc...
How to turn an int pointer to an array
Strictly speaking: You cannot.
Any pointer can be treated as an array. An array is a sort of 2nd class citizen, and in most places the compiler treats an array as a pointer, and whenever an array is passed to a function, the compiler actually passes the address of the first element of the array. In fact, a[b] is considered to be *(a + b) (which can lead to some pretty incomprehensible code!)
So in your structure, items can be treated as a plain integer pointer, or the address of an array (as is done here).

How to pass "pointer to a pointer" to a function that expects "pointer to array"

Consider this piece of code:
#define MAX 4
............
............
int** ptr = (int**)malloc(sizeof(int*)*MAX);
*ptr = (int*)malloc(sizeof(int)*MAX);
// Assigned values to the pointer successfully
How foo() can be invoked with ptr as parameter ? foo()'s prototype has been declared as below:
void foo(int arr[][MAX]);
You can't pass ptr as parameter to that foo function.
The memory layout of a 2-dimensional array (array of arrays) is quite different from that of an array of pointers to arrays.
Either change the function signature to accept a int** (and probably also size information), or define ptr to be a 2-dimensional array of the appropriate size.
I am going to assume the function foo in your example actually wants a 2-D array of int, with MAX columns and an unspecified number of rows. This works in C and C++ because of how the rows lay out in memory. All the elements in row N+1 appear contiguously after all the elements in row N.
The syntax int arr[][MAX] asks for a pointer to the first element of such a 2-D array, not an array of pointers to rows. I'll assume you want the 2-D array, and not an array of pointers.
First, you need to correctly allocate your elements. You haven't specified what the leftmost dimension of arr[][MAX] is, or where it comes from. I'll assume it's in the variable dim here:
int (*ptr)[MAX]; /* pointer first element of an int[][MAX] array */
/* Allocate a 2-D array of dim * MAX ints */
ptr = (int (*)[MAX]) malloc( dim * MAX * sizeof(int) );
Then, to call your function, just do foo( ptr ) and it'll work without errors or warnings.
To make your code cleaner (especially if you're using many of these 2-D arrays), you might consider wrapping the pointer type in a typedef, and writing a small function to allocate these arrays.
typedef int (*int_array_2d)[MAX];
int_array_2d alloc_int_array_2d( int dim1 )
{
return (int_array_2d) malloc( dim1 * MAX * sizeof(int) );
}
That way, elsewhere in your code, you can say something much simpler and cleaner:
int_array_2d ptr = alloc_int_array_2d( dim );
Use the type system to your advantage. The C and C++ syntax for the type and the typecast are ugly, and unfamiliar to most people. They look strange due to the precedence of * vs. []. If you hide it in a typedef though, it can help keep you focused on what you're trying to do, rather than understanding C/C++'s weird precedence issues that arise when you mix arrays and pointers.

Resources