Passing multi-dimensional arrays to functions in C - c

Why is it necessary to specify the number of elements of a C-array when it is passed as a parameter to a function (10 in the following example)?
void myFun(int arr[][10]) {}
Is it so because the number of elements is needed to determine the address of the cell being accessed?

Yes. It's because arr[i][j] means ((int *)arr)[i * N + j] if arr is an int [][N]: the pointer-arithmetic requires the length of a row.

The compiler needs to have an idea when the next row starts in memory (as a 2D array is just a continuous chunk of memory, one row after the other). The compiler is not psyche!

It is only necessary if you used static allocation for your array thought. Because the generate code create a continuous memory block for the array, like pointed out ruakh.
However if you use dynamic allocation it is not necessary, you only need to pass pointers.
Regards

Related

Equivalence between Subscript Notation and Pointer Dereferencing

It is more than one questions. I need to deal with an NxN matrix A of integers in C. How can I allocate the memory in the heap? Is this correct?
int **A=malloc(N*sizeof(int*));
for(int i=0;i<N;i++) *(A+i)= malloc(N*sizeof(int));
I am not absolutely sure if the second line of the above code should be there to initiate the memory.
Next, suppose I want to access the element A[i, j] where i and j are the row and column indices starting from zero. It it possible to do it via dereferencing the pointer **A somehow? For example, something like (A+ni+j)? I know I have some conceptual gap here and some help will be appreciated.
not absolutely sure if the second line of the above code should be there to initiate the memory.
It needs to be there, as it actually allocates the space for the N rows carrying the N ints each you needs.
The 1st allocation only allocates the row-indexing pointers.
to access the element A[i, j] where i and j are the row and column indices starting from zero. It it possible to do it via dereferencing the pointer **
Sure, just do
A[1][1]
to access the element the 2nd element of the 2nd row.
This is identical to
*(*(A + 1) + 1)
Unrelated to you question:
Although the code you show is correct, a more robust way to code this would be:
int ** A = malloc(N * sizeof *A);
for (size_t i = 0; i < N; i++)
{
A[i] = malloc(N * sizeof *A[i]);
}
size_t is the type of choice for indexing, as it guaranteed to be large enough to hold any index value possible for the system the code is compiled for.
Also you want to add error checking to the two calls of malloc(), as it might return NULL in case of failure to allocate the amount of memory requested.
The declaration is correct, but the matrix won't occupy continuous memory space. It is array of pointers, where each pointer can point to whatever location, that was returned by malloc. For that reason addressing like (A+ni+j) does not make sense.
Assuming that compiler has support for VLA (which became optional in C11), the idiomatic way to define continuous matrix would be:
int (*matrixA)[N] = malloc(N * sizeof *matrixA);
In general, the syntax of matrix with N rows and M columns is as follows:
int (*matrix)[M] = malloc(N * sizeof *matrixA);
Notice that both M and N does not have to be given as constant expressions (thanks to VLA pointers). That is, they can be ordinary (e.g. automatic) variables.
Then, to access elements, you can use ordinary indice syntax like:
matrixA[0][0] = 100;
Finally, to relase memory for such matrices use single free, e.g.:
free(matrixA);
free(matrix);
You need to understand that 2D and higher arrays do not work well in C 89. Beginner books usually introduce 2D arrays in a very early chapter, just after 1D arrays, which leads people to assume that the natural way to represent 2-dimensional data is via a 2D array. In fact they have many tricky characteristics and should be considered an advanced feature.
If you don't know array dimensions at compile time, or if the array is large, it's almost always easier to allocate a 1D array and access via the logic
array[y*width+x];
so in your case, just call
int *A;
A = malloc(N * N * sizeof(int))
A[3*N+2] = 123; // set element A[3][2] to 123, but you can't use this syntax
It's important to note that the suggestion to use a flat array is just a suggestion, not everyone will agree with it, and 2D array handling is better in later versions of C. However I think you'll find that this method works best.

In C: Is it faster to access a char* = malloc() used like a 2D array than an array[][]?

Just stumbled accross this recent question:
How can I have a dynamically allocated 2D array in C?
I just wondered: When I create a 2D array with a simple malloc and manage the 2D-like access myself like so:
int row=100;
int col=100;
char* buffer = malloc(sizeof(char)*row*col);
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
buffer[i*col+j]=128;
}
}
would this be (significantly) faster then when creating a 'conventional' 2D Array because in the former I achieve buffer optimization through sequential access? Or am I thinking wrong?
int row=100;
int col=100;
char buffer[row][col];
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
buffer[i][j]=128;
}
}
Thanks for your explanation.
Leaving the (small) overhead for dynamic memory allocation away, there is no difference if you access a particular element in a memory area by [row][column] or * (row * rowsize + column). It's basically just a difference in notation.
So your question is more like "is it better to have arrays defined "row first" than "column first?".
And the answer is: only you will know since you are the one to define the access pattern to the memory area depending on your application's needs.
I wouldn't think too much about this unless you deal with very large arrays (where one dimension is larger than what fits into your caches).
Note 1:
In the first code snippet, the array is allocated on the process's heap, while on the second snippet you allocate the buffer on the stack. If you want to use larger sized arrays, you might get a ... stackoverflow :)
Note 2:
My explain is focusing on the case where you want to allocate dynamically a 2D array, using Type** (int** in your case).
When you deal with a 2D array, it's faster to allocate it as a 1D array and use smart indexing to access it as a 2D array. This is because:
1D array fills a contiguous space in memory (lower fragmentation). This enables better caching of the array, decreasing the access latencies.
When you allocate a 2D array, you have another level of indirection, meaning that you need to get the address of the row first and then access the element. When you use a 1D array, you access directly the element.
When the array is allocated in 1D fashion, it's easily to align it to the cache line size. This will make it easier for the compiler to optimize transactions and avoid having to make 2 reads for an element that falls on a cache line boundary.
Dealing with 1D array, should help the compiler generate better vectorized code.

memcpy for multidimensional array

Is there a way we can copy every element from one multidimensional array to another multidimensional array by just doing one memcpy operation?
int array1[4][4][4][4];
int array2[4][4][4][4];
int main()
{
memset(&array1,1,sizeof(array1));
memset(&array2,0,sizeof(array2));
printf_all("value in array2 %d \n",array2[1][1][1][1]);
memcpy(&array2,&array1,sizeof(array2));
printf("memcopied in array2 from array1 \n");
printf("value in array2 %d \n",array2[1][1][1][1]); //not printing 1
}
Your code is correct. You should not expect the output to show you a value of 1. You should expect it to show you a value of 16843009, assuming a 4 byte int.
The reason is: you are filling array1 with bytes of value 1, not with ints of value 1. i.e. binary 00000001000000010000000100000001 (0x01010101) is being filled into all the int elements with your memset operation.
So regardless of the size of int on your machine (unless it's a single byte!) you should not expect to see the value 1.
I hope this helps.
Yes, your code should already be correct.
You have to consider memory layout when doing this. The arrays are all in one block, multi dimensional is essentially a math trick done by the compiler.
Your code says copy this memory content to the other memory block. since both share the same layout they will contain the same values.
The following code also just copies the values, but access is handled differently so you would have to think about how to get the order of elements correct.
int array1[4][4][4][4]; //elements 256
int array2[256];
int main()
{
memcpy(&array2,&array1,sizeof(array1)); //will also copy
// original access via: a + 4 * b + 16 * c + 64 * d
}
Multidimensional array in C is a flat block of memory with no internal structure. Memory layout of a multidimensional array is exactly the same as that of a 1-dimensional array of the same total size. The multidimensional interface is implemented through simple index recalculation. You can always memcpy the whole multidimensional array exactly as you do it in your code.
This, of course, only applies to built-in multidimensional arrays, explicitly declared as such (as in your code sample). If you implement a hand-made multidimensional array as an array of pointers to sub-arrays, that data structure will not be copyable in one shot with memcpy.
However, apparently you have some misconceptions about how memset works. Your memset(&array1,1,sizeof(array1)); will not fill the array with 1s, meaning that your code is not supposed to print 1 regardless of which array you print. memset interprets target memory as an array of chars, not as an array of ints.
memset can be used to set memory to zero. As for non-zero values, memset is generally unsuitable for initializing arrays of any type other than char.

Malloc or normal array definition?

When shall i use malloc instead of normal array definition in C?
I can't understand the difference between:
int a[3]={1,2,3}
int array[sizeof(a)/sizeof(int)]
and:
array=(int *)malloc(sizeof(int)*sizeof(a));
In general, use malloc() when:
the array is too large to be placed on the stack
the lifetime of the array must outlive the scope where it is created
Otherwise, use a stack allocated array.
int a[3]={1,2,3}
int array[sizeof(a)/sizeof(int)]
If used as local variables, both a and array would be allocated on the stack. Stack allocation has its pros and cons:
pro: it is very fast - it only takes one register subtraction operation to create stack space and one register addition operation to reclaim it back
con: stack size is usually limited (and also fixed at link time on Windows)
In both cases the number of elements in each arrays is a compile-time constant: 3 is obviously a constant while sizeof(a)/sizeof(int) can be computed at compile time since both the size of a and the size of int are known at the time when array is declared.
When the number of elements is known only at run-time or when the size of the array is too large to safely fit into the stack space, then heap allocation is used:
array=(int *)malloc(sizeof(int)*sizeof(a));
As already pointed out, this should be malloc(sizeof(a)) since the size of a is already the number of bytes it takes and not the number of elements and thus additional multiplication by sizeof(int) is not necessary.
Heap allocaiton and deallocation is relatively expensive operation (compared to stack allocation) and this should be carefully weighted against the benefits it provides, e.g. in code that gets called multitude of times in tight loops.
Modern C compilers support the C99 version of the C standard that introduces the so-called variable-length arrays (or VLAs) which resemble similar features available in other languages. VLA's size is specified at run-time, like in this case:
void func(int n)
{
int array[n];
...
}
array is still allocated on the stack as if memory for the array has been allocated by a call to alloca(3).
You definately have to use malloc() if you don't want your array to have a fixed size. Depending on what you are trying to do, you might not know in advance how much memory you are going to need for a given task or you might need to dynamically resize your array at runtime, for example you might enlarge it if there is more data coming in. The latter can be done using realloc() without data loss.
Instead of initializing an array as in your original post you should just initialize a pointer to integer like.
int* array; // this variable will just contain the addresse of an integer sized block in memory
int length = 5; // how long do you want your array to be;
array = malloc(sizeof(int) * length); // this allocates the memory needed for your array and sets the pointer created above to first block of that region;
int newLength = 10;
array = realloc(array, sizeof(int) * newLength); // increase the size of the array while leaving its contents intact;
Your code is very strange.
The answer to the question in the title is probably something like "use automatically allocated arrays when you need quite small amounts of data that is short-lived, heap allocations using malloc() for anything else". But it's hard to pin down an exact answer, it depends a lot on the situation.
Not sure why you are showing first an array, then another array that tries to compute its length from the first one, and finally a malloc() call which tries do to the same.
Normally you have an idea of the number of desired elements, rather than an existing array whose size you want to mimic.
The second line is better as:
int array[sizeof a / sizeof *a];
No need to repeat a dependency on the type of a, the above will define array as an array of int with the same number of elements as the array a. Note that this only works if a is indeed an array.
Also, the third line should probably be:
array = malloc(sizeof a);
No need to get too clever (especially since you got it wrong) about the sizeof argument, and no need to cast malloc()'s return value.

What is the reason C compiler demands that number of columns in a 2d array will be defined?

given the following function signature:
void readFileData(FILE* fp, double inputMatrix[][], int parameters[])
this doesn't compile.
and the corrected one:
void readFileData(FILE* fp, double inputMatrix[][NUM], int parameters[])
my question is, why does the compiler demands that number of columns will be defined when handling a 2D array in C? Is there a way to pass a 2D array to a function with an unknown dimensions?
thank you
Built-in multi-deminsional arrays in C (and in C++) are implemented using the "index-translation" approach. That means that 2D (3D, 4D etc.) array is laid out in memory as an ordinary 1D array of sufficient size, and the access to the elements of such array is implemented through recalculating the multi-dimensional indices onto a corresponding 1D index. For example, if you define a 2D array of size M x N
double inputMatrix[M][N]
in reality, under the hood the compiler creates an array of size M * N
double inputMatrix_[M * N];
Every time you access the element of your array
inputMatrix[i][j]
the compiler translates it into
inputMatrix_[i * N + j]
As you can see, in order to perform the translation the compiler has to know N, but doesn't really need to know M. This translation formula can easily be generalized for arrays with any number of dimensions. It will involve all sizes of the multi-dimensional array except the first one. This is why every time you declare an array, you are required to specify all sizes except the first one.
As the array in C is purely memory without any meta information about dimensions, the compiler need to know how to apply the row and column index when addressing an element of your matrix.
inputMatrix[i][j] is internally translated to something equivalent to *(inputMatrix + i * NUM + j)
and here you see that NUM is needed.
C doesn't have any specific support for multidimensional arrays. A two-dimensional array such as double inputMatrix[N][M] is just an array of length N whose elements are arrays of length M of doubles.
There are circumstances where you can leave off the number of elements in an array type. This results in an incomplete type — a type whose storage requirements are not known. So you can declare double vector[], which is an array of unspecified size of doubles. However, you can't put objects of incomplete types in an array, because the compiler needs to know the element size when you access elements.
For example, you can write double inputMatrix[][M], which declares an array of unspecified length whose elements are arrays of length M of doubles. The compiler then knows that the address of inputMatrix[i] is i*sizeof(double[M]) bytes beyond the address of inputMatrix[0] (and therefore the address of inputMatrix[i][j] is i*sizeof(double[M])+j*sizeof(double) bytes). Note that it needs to know the value of M; this is why you can't leave off M in the declaration of inputMatrix.
A theoretical consequence of how arrays are laid out is that inputMatrix[i][j] denotes the same address as inputMatrix + M * i + j.¹
A practical consequence of this layout is that for efficient code, you should arrange your arrays so that the dimension that varies most often comes last. For example, if you have a pair of nested loops, you will make better use of the cache with for (i=0; i<N; i++) for (j=0; j<M; j++) ... than with loops nested the other way round. If you need to switch between row access and column access mid-program, it can be beneficial to transpose the matrix (which is better done block by block rather than in columns or in lines).
C89 references: §3.5.4.2 (array types), §3.3.2.1 (array subscript expressions)
C99 references: §6.7.5.2 (array types), §6.5.2.1-3 (array subscript expressions).
¹ Proving that this expression is well-defined is left as an exercise for the reader. Whether inputMatrix[0][M] is a valid way of accessing inputMatrix[1][0] is not so clear, though it would be extremely hard for an implementation to make a difference.
This is because in memory, this is just a contiguous area, a single-dimension array if you will. And to get the real offset of inputMatrix[x][y] the compiler has to calculate (x * elementsPerColumn) + y. So it needs to know elementsPerColumn and that in turn means you need to tell it.
No, there's not. The situation's pretty simple really: what the function receives is really just a single, linear block of memory. Telling it the number of columns tells it how to translate something like block[x][y] into a linear address in the block (i.e., it needs to do something like address = row * column_count + column).
Other people have explained why, but the way to pass a 2D array with unknown dimensions is to pass a pointer. The compiler demotes array parameters to pointers anyway. Just make sure it's clear what you expect in your API docs.

Resources