Passing 1D array, 2D arrays and pointer Arrays - c

To pass a 1D array to a function, we do this:
#include <stdio.h>
#include <stdlib.h>
void func(int *arr, int n)
{
// code here
}
int main()
{
int arr[] = {......}; // declare array
int n = sizeof(arr)/sizeof(arr[0]);
func(arr); // calling function func
return 0;
}
To pass a 2D array to a function, we do this:
#include <stdio.h>
#include <stdlib.h>
void func(int arr[][2])
{
// code here
}
int main()
{
int arr[3][2]; // declare 2D array
func(arr); // calling function func
return 0;
}
So while passing a pointer array to a function, can we do something like this?
#include <stdio.h>
#include <stdlib.h>
void func(int **arr, int n)
{
// code here
}
int main()
{
int *arr[] = {......}; // declare array of pointers
int n = sizeof(arr)/sizeof(arr[0]);
func(arr, n); // calling function func
return 0;
}
I am confused with pointers and arrays to be honest. It took me a long time to figure out how to pass a 2D array. I tried searching other similar questions, but to no avail. Please help me with: Passing a pointer array to a function. Also, any links where I can clear the confusion will be really appreciated.

In your last example, you have an array of pointers.
And yes, that would work, check for example this toy example:
#include <stdio.h>
#include <stdlib.h>
void func(int **arr, int n) {
// print equal to arr[0][1]
printf("%d %d\n", n, *arr[1]);
}
int main(void) {
int a = 1, b = 2, c = 3;
// set the points of a, b, and c, to arr[0][0..2];
int *arr[] = {&a, &b, &c};
int n = sizeof(arr)/sizeof(arr[0]);
printf("%d %d\n", n, *arr[1]);
func(arr, n);
return 0;
}
Output:
3 2
3 2

I am confused with pointers and arrays to be honest. It took me a long time to figure out how to pass a 2D array.
This confusion is very widespread. It stems from the fact that you cannot pass arrays in C, but the language allows a syntax that makes it look like you could.
So, as you can't pass an array to a function, what you do instead is pass it a pointer to the first array element and, if needed, the size of the array. Inside the function, you can use that pointer for accessing the array, and the syntax looks the same as if it would be an actual array. This also needs some explanation:
[], the indexing operator, works by adding the index to a given pointer and dereferencing the resulting pointer. Therefore, writing a[5] is exactly the same as *(a+5).
This even works if a is an actual array (and not a pointer), because an array evaluates to a pointer to the first element in most contexts (there are exceptions like the sizeof operator).
To make things more complicated, C allows to declare functions that look as if they were taking arrays, e.g. you can write:
void foo(int bar[]);
There's a rule in the C standard that says function parameter types are subject to "type adjustment": Any parameter of an array type is automatically adjusted to the corresponding pointer type. So, the function above is actually the same as
void foo(int *bar);
Therefore, better forget about passing arrays (I'd even recommend to not use the array syntax in function parameters, but that's subject to debate) -- you always pass pointers.
With this knowledge, you can easily construct correct examples for all your cases:
(1) "Normal" array:
void foo(int bar[], size_t n); // with type adjustment
void foo(int *bar, size_t n); // what it really means
// call like
int a[5];
foo(a, 5);
(2) 2D array:
A 2D array is an array of arrays, so it's first element is itself an array -> you would pass a pointer to an array
void foo(int bar[][10], int n); // with type adjustment, 2d array of n x 10
void foo(int (*bar)[10], int n); // what it really means
// call like:
int a[5][10];
foo(a, 5);
(3) Array of pointers:
An array of pointers is often used as an alternative to a 2d array -- as the elements are just pointers, they can point to single values or arrays of different lengths, but the drawback is that you don't have the whole data as a single block in memory, as would be the case with a real 2d array. As this is just an array of pointers, it looks very much like a "normal" array in use:
void foo(int *bar[], int n); // with type adjustment
void foo(int **bar, int n); // what it really means
// call like:
int *a[5];
foo(a, 5);
Final note: You will often read that arrays "decay as pointers" in C. That's no official wording, but very widespread. If you combine the rule that an array identifier evaluates to a pointer in most contexts (e.g. when passing it to a function) with the rule of type adjustment for function parameters, the result is that you write array syntax everywhere, but get pointers, so that's the meaning of "decaying".

There is actually no differences among 1-D array, 2-D array, X-D array and pointer array. All of them are just consequent memory area.
1-D array:
int arr[8];
int *addr = arr;
| arr[0] | ...*6... | arr[7] |
^ ^
| |
addr addr+7
2-D array:
int arr[4][2]
int *addr = arr[0];
| arr[0][0] | ...*6... | arr[3][1] |
^ ^
| |
addr addr+7
3-D array:
int arr[2][2][2];
int *addr = arr[0][0];
| arr[0][0][0] | ...*6... | arr[1][1][1] |
^ ^
| |
addr addr+7
pointer array:
typedef pointer int*;
...
int a0[8] = {0, 1, 2, 3, 4, 5, 6, 7};
int a1[7] = {0, 1, 2, 3, 4, 5, 6};
...
int a7[1] = {0};
pointer arr[8] = {a0, a1, a2, a3, a4, a5, a6, a7};
pointer *addr = arr;
| arr[0] = a1 | ...*6... | arr[7] = a7 |
^ ^
| |
addr addr+7
Defining an X-D array can be implemented as following:
typedef data_type int;
typedef struct X-Array
{
int d1;
int d2;
...
int dx;
data_type *data;
} X-Array;
X-Array *create_X_Array(int d1, int d1, ..., int dx)
{
X-Array *arr;
if ((arr = malloc(sizeof(X-Array))) == NULL)
return NULL;
if ((arr->data = malloc(sizeof(data_type * d1 * d2 * ... * dx))) == NULL)
{
free(arr);
return NULL;
}
arr->d1 = d1;
arr->d2 = d2;
...
arr->dx = dx;
return arr;
}

Related

Why can't int (*p)[] be used as an argument for C function?

#include <stdio.h>
void print(int (*p)[3]);
int main(void)
{
int a[3] = {1, 2, 3};
print(&a);
return 0;
}
void print(int (*p)[3])
{
for (int i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
I have written a C function. See above.
It can print all the elements in an array.
There is one thing which is not so perfect : The number of array elements seems to be known in advance.
So I made some modification in hopes of making the function universal :
#include <stdio.h>
void print(int (*p)[]);
int main(void)
{
int a[3] = {1, 2, 3};
print(&a);
return 0;
}
void print(int (*p)[])
{
for (int i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
In the function, p is pointer pointing to the entire array.
However, it fails to be compiled.
Why can't int (*p)[] be used as an argument for C function?
int (*p)[] can be used as an argument for the function. The part of your code that gives the error is sizeof *p which is obviously not possible, because the type of *p is int[] which is an incomplete type and hence has no known size.
For the function to know the length of the array, you must design a way for the function to receive this information. Options include:
what you did in the original code.
passing the length as another argument.
including the length as an array element.
having a sentinel value on the end of the array.
The most common idiom would be to pass int *p, size_t n, you do not really gain anything by using pointer-to-array without the dimension being given.
The problem is that int [] is an incomplete type as the array has no defined size and therefore its sizeof cannot be taken.
In "modern C" (i.e. for almost 2 decades) you could have used variable-length arrays for this - you can pass the size as an argument and then the array:
#include <stdio.h>
#include <stdlib.h>
void print(size_t n, int (*p)[*]);
int main(void) {
int a[3] = {1, 2, 3};
print(3, &a);
}
void print(size_t n, int (*p)[n]) {
for (size_t i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
Of course this gains you nothing, since sizeof *p / sizeof **pp will be ... n. Therefore we might as well have used
void print(size_t n, int p[n]) {
for (size_t i = 0; i < p; i++)
printf("%d\n", p[i]);
}
which is less typing.
Short answer: int (*p)[] can't be used as an argument and have the function magically know the array size, because the standard says so.
Longer answer:
int (*p)[] is a pointer to an array, but the array has no defined size. So by looking at the array, it is impossible to do pointer arithmetic, calculate size of the thing p is pointing at, etc..
You don't have array of arrays so you don't need int (*p)[]. You have an array of int, so int *p or int p[] should be enough. This does not solve the problem of knowing the size of your array in print. To do this you basically have 3 options
Hardcode the value in the function
Put a sentinel value in your array to mark the end
Pass the size as a separate parameter like this:
void print(int n, int p[n])
Just remember that whatever method you use, parameter passing of arrays will always use pointers behind the scenes, so you CAN NOT use sizeof(p) to calculate the size of the array. sizeof will always return the size of a pointer in those situations

How to cast back to multidimensional?

How to cast back from void* ?
int *a[13][12];
void *b
int *c[13][12];
b = (void*) a;
c = (?????) b;
This
c = (int *[13][12])b;
says cast specifies array type
This
c = (int *[][])b;
says array type has incomplete element type.
Compiler is gcc (Ubuntu/Linaro 4.6.1)
In C, you cannot assign to an array, so since c is declared as an array of arrays of pointers to ints, you can't assign it directly.
You could however overwrite all of its items by assigning c[i][j] in turn inside a for loop, for example.
c and a are arrays not pointers, see above, you can use a pointer to a (2 dim) array like
int a[13][12] ={ 1,2,3 };
void *b = &a;
int (*c)[13][12] = b;
and all that without casts
You cannot assign directly to an array, or cast to an array type in C. However, since arrays decay to pointers, you can copy the data from a void * pointer (i.e.: memcpy) to an array and use it as an array, e.g.:
#include <stdio.h>
#include <string.h>
int main() {
int a1=1, a2=2, a3=3, a4=4;
int *a[2][2] = { { &a1, &a2 }, { &a3, &a4 } };
printf("%d %d %d %d\n", *a[0][0], *a[0][1], *a[1][0], *a[1][1]);
void *b;
b = (void*) a;
int *c[2][2];
memcpy(c, b, sizeof(c));
printf("%d %d %d %d\n", *c[0][0], *c[0][1], *c[1][0], *c[1][1]);
return 0;
}
Compiling and running the following program will give you:
1 2 3 4
1 2 3 4
However, c and a are two different arrays now.

I'm trying to make 2d array, pass it to function and then update the modified array in main

The compiler shows:
Warning: passing argument 1 of 'fun' from incompatible
pointer type; note: expected 'int ()[5]' but argument
is of type 'int (*)[5][5]'
Code:
#include<stdio.h>
void fun(int * b[][5])
{
int x=11,y=90;
printf("here");
*b[1][3] = x;
*b[3][1] = y;
*b[2][2] = x + ++y;
}
int main()
{
int a[5][5];
a[1][3] = 12;
a[3][1] = 145;
fun(&a);
printf("%d %d %d",a[1][3],a[3][1],a[2][2]);
}
You do not need the asterisk in your function parameters, and you don't need to dereference the array b in your function. Arrays are passed by reference (so get rid of the ampersand in foo(&a) as well), because C treats them as pointers to the first element in the sequence.
Multidimensional arrays are treated as arrays of pointers to the start of smaller sub-arrays, i.e. arrays-of-arrays. Same explanation as above applies.
Your code should look like this in the end:
void fun(int b[][5]) // can also be (int (*b)[5]), i.e. array of 5 pointers
{
int x=11,y=90;
b[1][3] = x;
b[3][1] = y;
b[2][2] = x + ++y;
}
int main()
{ // ...
fun(a);
// ...
}
int a[5][5]; //is an 2d int array
When arrays are passed to a function, what really gets passed is a pointer to the arrays first element.
So calling the fun() function with fun(a) will actually pass the pointer to the a first element, in this case an int array of size 5. The function fun() will receive a pointer to an int array of size 5, that is to say int (*b)[5]. Note that int *b[5] is not the same and is an array of size 5 containing int pointers.
Your fun function can either have:
void fun(int b[][5])
or
void fun(int (*b)[5])
The first way to do it says that the function will receive a 2d array of ints, but since we know that what actually will be sent to the function is a pointer to the first element of the array a, the compiler will quietly compile the function as if the parameter were a pointer, since it's a pointer that it will receive.
The second way to do it explicitly shows what type it will receive, a pointer to an array of size 5.

Why does this generate a segmentation fault?

#include<stdio.h>
void foo(int **arr) {
arr[1][1]++;
}
main() {
int arr[20][20];
printf("%d\n",arr[1][1]);
foo((int**)arr);
printf("%d\n",arr[1][1]);
}
Suppose you declare:
int arr[ 10 ][ 20 ] ;
What type is arr?
You may think that it's int **, but that's incorrect.
Its actually of type int (*)[20] when it decays (like when you pass it to a function);
Array decaying applies only once.
Details here
Now consider the following,
#include<stdio.h>
#include<stdlib.h>
void foo(int arr[][20]) {
arr[1][1]++;
}
main() {
int (*arr)[20];
arr = malloc(sizeof(int (*)[]) * 2); //2 rows & malloc will do implicit cast.
printf("%d\n",arr[1][1]);
foo(arr);
printf("%d\n",arr[1][1]);
}
Output :
$ gcc fdsf.c && ./a.out
0
1
arr and arr+1 are pointing to array of 20 integers.
arr + 0 --> int int int ... int (20 ints, contiguous)
[0][0] [0][1]
arr + 1 --> int int int ... int (20 ints, contiguous)
[1][0] [1][1]
Here's what an int[2][2] looks like in memory:
int[2] int[2]
That is, an array immediately followed by another array.
Here's what an int[2] looks like in memory:
int int
That is, an int immediately followed by another int.
So, here's also what an int[2][2] looks like in memory:
int int int int
^ ^
| |___ this is arr[1][1]
|
|____ this is p[1], assuming sizeof(int*) == sizeof(int)
If you cast arr to an int**, I'm going to call the result p. Then it points to the same memory. When you do p[1][1] you don't get arr[1][1]. What the program does instead is, it reads the value at p[1], adjusts that up by the size of an int, and dereferences it. If that second int contained, say, the value "21" then you have just tried to dereference the pointer "25" (if int is 4 bytes). That ain't right.
Arrays are not the same as pointers, and 2-D arrays are certainly not the same thing as pointers-to-pointers.
Because foo expect a pointer to a pointer to int and you are passing it a pointer to an array of 20 int. Casting it won't change the fact that it isn't the correct type.
If you change it like this, you get the expected result:
#include<stdio.h>
void foo(int arr[][20]) {
arr[1][1]++;
}
int
main() {
int arr[20][20];
arr[1][1] = 1;
printf("%d\n",arr[1][1]);
foo(arr);
printf("%d\n",arr[1][1]);
}
foo needs to know the array size (well, at least the second array dimension, first isn't needed), otherwise it can't do the necessary pointer arithmetic for the [1][1].
Problem is that int arr[20][20] for 2d array means that this array is stored as 1d array, and lines are stored one after other. when you do indexing to int **arr you actually take 2nd element from first line of array, then you dereference it and take first element there.

Passing arrays and matrices to functions as pointers and pointers to pointers in C

Given the following code:
void
foo( int* array )
{
// ...
}
void
bar( int** matrix )
{
// ...
}
int
main( void ) {
int array[ 10 ];
int matrix[ 10 ][ 10 ];
foo( array );
bar( matrix );
return 0;
}
I don't understand why I get this warning:
warning: passing argument 1 of ‘bar’ from incompatible pointer type
Although 'foo' call seems to be ok.
Thanks :)
Well, it's certainly not well understood by the C community as can be seen by glancing over SO. The magic is, all of the following are totally, 100%, equivalent:
void foo(int (*array)[10]);
void foo(int array[][10]);
void foo(int array[10][10]);
void foo(int array[42][10]);
It is very important to draw the distinction of a pointer and an array. An array is not a pointer. An array can be converted to a pointer to its first element. If you have a pointer you have this:
--------
| ptr | -------> data
--------
However, if you have an array, you have this:
---------------------------
| c1 | c2 | c3 | ... | cn |
---------------------------
With the pointer, the data is at a whole other planet, but linked to by the pointer. An array has the data itself. Now, a multi-dimensional array is just an array of arrays. The arrays are nested into a parent array. So, the sizeof of your array is:
(sizeof(int) * 10) * 10
That is because you have 10 arrays, all of which are arrays of 10 integers. Now, if you want to pass that array, it is converted. But to what? A pointer to its first element. The element type is not a pointer, but an array. As a consequence, you pass a pointer to an array of 10 int:
int (*)[10] // a pointer to an int[10]
It is neither a array of int*, nor a int**. You may ask why the array is not passed as an int**. It's because the compiler has to know the row-length. If you do an array[1][0], the compiler will address a place sizeof(int) * 10 bytes apart from the begin of the 2 dimensional array. It decodes that information in the pointer-to-array type.
So, you have to chose among one of the above fully equivalent function prototypes. Naturally, the last one is just confusing. The compiler just silently ignores any number written in the most outer dimension if a parameter is declared to be an array. So i would also not use the second last version. Best is to use the first or second version. What is important to remember is that C has no (real) array parameters! The parameter will be a pointer in the end (pointer to array in this case).
Note how the multi-dimensional case of above is similar to the degenerate, one dimensional case below. All of the following 4 versions are fully equivalent:
void foo(int *array);
void foo(int array[]);
void foo(int array[10]);
void foo(int array[42]);
Passing multi-dimensional arrays in C is a tricky subject. See this FAQ.
The question to ask is how you'll be using bar. If you always know it will be passed a 10x10 array then rewrite it as
bar(int matrix[10][10]);
If you want to cope with arrays of varying dimensions then you might have to pass in the lengths:
bar(int *matrix, int width, int height);
The problem is that the data structure matrix[10][10] is actually not a table of ten pointers to array[10]'s, but it is an sequential array of 100 integers. The proper signature for bar is
bar (int matrix[10][10])
If you actually want to represent the matrix using indirection and have int **matrix as the parameter type for bar, then you need to allocate it differently:
int *matrix[10];
int my_data[100];
int i;
for (i = 0; i < 10; i++) { matrix[i] = &(my_data[i * 10]); }
bar(matrix);
Now 'matrix' matches the type int **. 'matrix' is an array of ten pointers, and you can pass it by pointer, hence getting the second *.
Here is some code to practice on - it contains all possible types of passing 2dimensional array and code to access element values
#include <stdio.h>
#define NUMROWS 2
#define NUMCOLUMNS 5
#define FILL_ARRAY() \
*array[0] = '1'; \
(*array)[7] = '2'; \
*(array[1]) = '3'; \
*(*(array+1)+1) = '4'; \
*(array[0]+3) = '5'; \
*(*array+2) = '7'; \
array[0][1] = '6';
void multi_01( char (*array)[NUMCOLUMNS] ) { FILL_ARRAY(); }
void multi_02( char array[][NUMCOLUMNS] ) { FILL_ARRAY(); }
void multi_03( char array[NUMROWS][NUMCOLUMNS] ) { FILL_ARRAY(); }
void multi_04( char **array ) { FILL_ARRAY(); }
void multi_05( char *array[] ) { FILL_ARRAY(); }
void multi_06( char *array[NUMCOLUMNS] ) { FILL_ARRAY(); }
int main(int argc, char **argv)
{
int i;
char mystr[NUMROWS][NUMCOLUMNS] = { { 'X', 'X', 'X', 'X'}, {'X','X','X'} };
char *pmystr[sizeof(mystr)/sizeof(*mystr)];
int numcolumns = sizeof(*mystr);
int numrows = sizeof(mystr)/sizeof(*mystr);
for( i=0; i<numrows; i++ ) pmystr[i] = *(mystr+i);
multi_01( mystr ); multi_02( mystr ); multi_03( mystr );
multi_04( pmystr ); multi_05( pmystr ); multi_06( pmystr );
printf("array '%s', '%s'\n", mystr[0], mystr[1]);
getc(stdin);
return 0;
}
You should define bar as:
bar( int* matrix )
In C all arrays should be passed as int* (or type_of_element* for other types).
int ** would be ok if your data was really an array of pointers. int[*data[] for example. Thats what you get in main(int argc, char *argv[]).
int **matrix
would indicate that you have a pointer to a pointer to int. That's commonly used to indicate a pointer to an array of pointers (also called a vector). That's definitely NOT the case with
int matrix[10][10]
which is a more of a pointer to a single section of memory sized for 10x10 ints. Try changing to:
void bar(int *matrix[])

Resources