C pointer with 2D array - c

I'm learning C language, and I'm confused in 2D array pointer.
I have the following declaration
int a[3][5];
int *b[3][3];
int (*c)[3][5];
int *(d[3][5]);
int (*e[3])[5];
could anyone help me clarify
if there're valid declaration or not
the sizeof a,b,c,d,e (assume on 64-bit machine, address id 8 bytes)
what they point to
how to access the element in the 2D array
I'm totally confused about the usage of pointer in 2D array.....and I guess some of them are equivalent...but some might not be good practice

These
int a[3][5];
int *b[3][5];
(I think you mean indeed int *b[3][5] instead of int *b[3][3] as it is written in your question)
two declarations of two-dimensional arrays.
Elements of the first array have type int.
Elements of the second array have type int *.
To access elements of the arrays you can use for example subscripting like
a[i][j] or b[i][j] where i is an index in the range [0,3) and j is an index in the range [0, 5).
For the second array to access objects pointed to by the elements of the array you can use expressions like *b[i][j]
sizeof( a ) is equal to 3 * sizeof( int[5] ) that in turn is equal to 3 * 5 * sizeof( int ).
sizeof( b ) is equal to 3 * sizeof( int *[5] ) that in turn is equal to 3 * 5 * sizeof( int *).
This
int (*c)[3][5];
is a declaration of a pointer to a two-dimensional array of the type int[3][5].
You can write for example
int (*c)[3][5] = &a;
where a is the two-dimensional array declared above.
To access elements of the pointed array you can use this syntax
( *c )[i][j]
This
int *(d[3][5]);
a declaration of a two-dimensional array elements of which have type int *.
This declaration is equivalent to the declaration shown above that is to
int *b[3][5];
You may enclose declarators in parentheses. So you could even write the declaration of the array d like
int * (((d)[3])[5]);
This
int (*e[3])[5];
is a declaration of an array with 3 elements of pointers to arrays of the type int[5].
Using the typedef
typedef int T[5];
the array declaration can be rewritten like
T * e[3];
Here a demonstrative program that shows how elements of the array e can be accessed.
#include <stdio.h>
int main( void )
{
int a1[5] = { 1, 2, 3, 4, 5 };
int a2[5] = { 10, 20, 30, 40, 50 };
int a3[5] = { 100, 200, 300, 400, 500 };
int(*e[3])[5] = { &a1, &a2, &a3 };
for (size_t i = 0; i < sizeof( e ) / sizeof( *e ); i++)
{
for (int j = 0; j < sizeof(*e[i]) / sizeof(**e[i]); j++)
{
printf( "%3d ", ( *e[i] )[j] );
}
putchar( '\n' );
}
return 0;
}
The program output is
1 2 3 4 5
10 20 30 40 50
100 200 300 400 500

Related

Is this a correct way to define array of pointers to array?

Is this a correct way to define array of pointers to array in C programming language?
int* ptr[2];
int n1[5] = { 2,3,4,5,6 };
int n2[5] = { 2,3,4,5,6 };
ptr[0] = &n1;
ptr[1] = &n2;
I am getting errors like:
epi_2.c:20:12: warning: incompatible pointer types assigning to 'int *' from 'int (*)[5]' [-Wincompatible-pointer-types]
ptr[1] = &n2;
You have to write
ptr[0] = n1;
ptr[1] = n2;
Array designators used in expressions with rare exceptions are converted to pointers to their first elements.
That is in the above statements expressions n1 and n2 have the type int * - the type of the left side expressions.
As for these statements
ptr[0] = &n1;
ptr[1] = &n2;
then the right side expressions have the type int ( * )[5] that is not compatible with the type int * of the left side expressions. So the compiler issues messages.
Otherwise you need to declare the array of pointers like
int ( * ptr[2] )[5];
//...
ptr[0] = &n1;
ptr[1] = &n2;
Here is a demonstration program.
#include <stdio.h>
int main( void )
{
int* ptr[2];
int n1[5] = { 2,3,4,5,6 };
int n2[5] = { 2,3,4,5,6 };
ptr[0] = n1;
ptr[1] = n2;
for ( size_t i = 0; i < 2; ++i )
{
for ( size_t j = 0; j < 5; j++ )
{
printf( "%d ", ptr[i][j] );
}
putchar( '\n' );
}
}
The program output is
2 3 4 5 6
2 3 4 5 6
And here is another demonstration program.
#include <stdio.h>
int main( void )
{
int ( * ptr[2] )[5];
int n1[5] = { 2,3,4,5,6 };
int n2[5] = { 2,3,4,5,6 };
ptr[0] = &n1;
ptr[1] = &n2;
for ( size_t i = 0; i < 2; ++i )
{
for ( size_t j = 0; j < 5; j++ )
{
printf( "%d ", ( *ptr[i] )[j] );
}
putchar( '\n' );
}
}
The program output is the same as shown above
2 3 4 5 6
2 3 4 5 6
Is this a correct way to define array of pointers to array?
&n1 does return a pointer to an array.
But ptr[0] is not a pointer to an array. It's a pointer to an int.
You have two options.
Change ptr[0] to be a pointer to an array
By using the following, ptr becomes an array of pointers to arrays of 5 ints.
int ( *ptr[2] )[5] = { &n1, &n2 };
Change &1n to something that returns a pointer to int
But we rarely deal with pointer to arrays. We usually work with pointers to the first element of the array.
int *ptr[2] = { &( n1[0] ), &( n2[0] ) };
Because an array degenerates into a pointer to its first element, the following is equivalent but shorter:
int *ptr[2] = { n1, n2 };
In both cases, you end up with a pointer to the same address. But the type of the pointer is different. About the only difference is that sizeof( *ptr[0] ) will vary.
#include <stdio.h>
int main( void ) {
int ( *ptrA[2] )[5];
int *ptrB[2];
printf( "%zu\n", sizeof( *ptrA[0] ) ); // 20, size of array of 5 `int`.
printf( "%zu\n", sizeof( *ptrB[0] ) ); // 4, size of one `int`.
}
In C, there are two kinds of pointers to arrays:
Pointers that point to the first element of the array.
Pointers that point to the array as a whole.
If you have an array
int arr[5] = { 2,3,4,5,6 };
then you can create a pointer to the first element of the array the following way:
int *ptr = arr;
In the line above, the expression arr will automatically decay to &arr[0], i.e. to a pointer to the first element of the array.
You can create a pointer to the array as a whole the following way:
int (*ptr)[5] = &arr;
In C, it is more common to use the first kind of pointer. However, which kind of pointer you want depends on the situation.
For example, do you want sizeof *ptr to evaluate to the size of the entire array? Or do you want that expression to evaluate to the size of a single element of the array?
Also, how do you want ptr++ to behave? Do you want the pointer jump to the next element of the array? Or do you want the pointer to jump over the entire array (for example because you are using an array of arrays and want to jump to the next element of the outer array)?
If you want sizeof *ptr to evaluate to the size of a single element and want ptr++ to jump to the next element of the array, then you want the first kind of pointer. However, if you want sizeof *ptr to evaluate to the size of the entire array and want ptr++ to jump over the entire array, then you want the second kind of pointer.
If in doubt, I recommend that you chose the first kind of pointer, because that kind of pointer is easier to handle and more common.
Once you have decided which kind of pointer you want, you can then create an array of these pointers.
If you want an array of the first kind of pointer, then you can define that array like this:
int *ptrs[2];
ptrs[0] = n1;
ptrs[1] = n2;
If you instead want an array of the second kind of pointer, then you can define that array like this:
int (*ptrs[2])[5];
ptrs[0] = &n1;
ptrs[1] = &n2;

Printing a multidimensional array in C

I am trying to print a 2-D array in C by using pointers but I am not getting the expected output.
Program:-
#include <stdio.h>
int main()
{
int arr[2][3] = {{1,2,3},{4,5,6}};
int* p;
for ( p = arr; p <= arr+6; p++)
{
printf("%d ", *p);
}
return 0;
}
Output:-
1 2 3 4 5 6 -1116112128 1587637938 0 0 1893963109 32521 -1453950296 32766 -1453805568 1 800797033 21984 -1453949463
Could you tell me where I am wrong as the output should only be:
1 2 3 4 5 6
Could you tell me where I am wrong
The elements of arr are not integers, but arrays of 3 integers. So arr+6 is surely a different address than what you expect, since pointer arithmetic works in multiples of the size of the type in the array.
You'll always be better off using nested loops to iterate over a multidimensional array; treating it as one single-dimensional array of int leads to exactly the kinds of confusion you see here. The code is harder to understand and verify, it won't be any slower.
First, when looping through arrays of size n wth an index i, the condition for continuation should be i < n rather than i <= n, because array indexes in C run from 0 through n-1.
However, your code has a more serious error: 1-dimensional arrays can be 'decayed' into pointers to the elements' type; however, 2-dimensional arrays decay into pointers to 1-dimensional arrays. So, in your case, the type of the pointer used in the arr + 6 expression is a pointer to an array of three integers; further, when the 6 is added, that operation is performed in terms of the size of the pointed-to object, which is sizeof(int) * 3 – so, even when changing the <= to <, you will be running far beyond the actual bounds of the array.
To make the pointer arithmetic work in the correct 'units' (i.e. sizeof(int)), cast the arr to an int* before the addition (and also change the <= to <):
#include <stdio.h>
int main()
{
int arr[2][3] = { {1,2,3},{4,5,6} };
int* p;
for (p = (int*)arr; p < (int*)arr + 6; p++) {
printf("%d ", *p);
}
return 0;
}
You are trying to access the value in the wrong way, The two-dimensional array is saved as a continuous block in the memory. So, if we increment the value of ptr by 1 we will move to the next block in the allocated memory.
int arr[2][3] = {{1,2,3},{4,5,6}};
int *ptr = arr;
int i,j;
for (i = 0; i < 6; i++) {
printf("%d ", *(ptr + i));
}
return 0;
Array designators used in expressions with rare exceptions are implicitly converted to pointers to their first elements.
The type of the array elements of this array
int arr[2][3];
is int [3]. So a pointer to the first element of the array has the type int ( * )[3].
This assignment
p = arr;
where p has the type int * is incorrect because the operands of the assignment have incompatible pointer types.
At least you need to cast the right expression to the type int * like
p = ( int * )arr;
The same casting you need to use in the condition in the for loop. That is instead of
p <= arr+6
you have to write
p < ( int * )arr+6
Below there is a demonstration program that shows how to output a two-dimensional array as a two-dimensional array using pointers.
#include <stdio.h>
int main( void )
{
int arr[2][3] = {{1,2,3},{4,5,6}};
for ( int ( *p )[3] = arr; p != arr + 2; p++ )
{
for ( int *q = *p; q != *p + 3; ++q )
{
printf( "%d ", *q );
}
putchar( '\n' );
}
return 0;
}
If you want to output the two-dimensional array as a one-dimensional array then you can write
#include <stdio.h>
int main( void )
{
int arr[2][3] = {{1,2,3},{4,5,6}};
for ( int *p = ( int * )arr; p != ( int * )arr + 6; p++ )
{
printf( "%d ", *p );
}
putchar( '\n' );
return 0;
}
In
for ( p = arr; p <= arr+6; p++)
the expression arr, as an rvalue, is a pointer to the first element of the array (which is of type int [3], so each time you increment that pointer, it moves three int positions forward ---a whole row---, and so, arr + 6 points just after the sixth row of the array (if the array should ever had six rows) You can do it (with the proper explicit pointer conversions, as you are mixing pointers to int with pointers to int [3]) with the expression arr + 2 which is the addres of the first array element after the second row (and the number of rows of the array).
You can do it also declaring
int (*aux)[2][3] = &arr; /* aux is a pointer to the whole 3x2 array,
* so aux + 1 will be the position of the second
* 2D array after this one */
and then
int *end = (int *)(aux + 1);
or simply
int *end = (int *)(&arr + 1); /* see below */
(Beware that arr and &arr are both pointers and point to the same place, but they are not the same type (arr is of type int (*)[3] and &arr is of type int(*)[2][3])
So let's rewrite your code as
for (p = (int *)arr; p < end; p++)
or
for (p = (int *)arr; p < (int *)&arr + 1; p++)
would work, which seems more natural to do the calculus in complete array units than in rows or single cells (and you can change freely the dimensions of the array)
Your code would be:
#include <stdio.h>
int main()
{
int arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
int *end = (int *)(&arr + 1); /* try to avoid evaluating this expression in the loop
* despite that it can be optimized to comparing
* with a constant value */
char *sep = "";
for (int *p = (int *)arr; p < end; p++)
{
printf("%s%d", sep, *p);
sep = ", ";
}
putchar('\n');
return 0;
}
(Beware that you have to use < operator and not <= as you don't want to print the value pointed by end, because it lies one place outside of the array)
Finally a note: this will work with true arrays, but not with function parameters declared as arrays, because they decay to pointers and then &arr is not a pointer to data the size of the array, but it is the address of the parameter itself, which points to the array somewhere else.

Swapping 2 arrays in C

I need to swap the values of 2 arrays in a function. The problem is I can change anything in the main, just the function itself. It should recive 2 integer arrays, and swap those. The problem is, that I don't know the size of the arrays, and for my understading they can even be in diffrent sizes. Trying this code:
int main()
{
int size = 4; //Please notice that I'm using this only to print the array
int a[] = {1,2,3,4};
int b[] = {5,6,7,8};
printArr(a,"a",size);
printArr(b,"b",size);
swapArray(a,b);
printf("Swapped:\n");
printArr(a,"a",size);
printArr(b,"b",size);
}
and this function:
void swapArray(int **a,int **b)
{
int *p = *a;
*a = *b;
*b = p;
}
while printArr simply prints the array:
void printArr(int arr[],char name[],int size)
{
printf("%s:\t",name);
for(int i=0;i<size;i++){
printf("%d\t",arr[i]);
}
printf("\n");
}
I got a really weird result:
a: 1 2 3 4
b: 5 6 7 8
Swapped:
a: 5 6 3 4
b: 1 2 7 8
I would like to understand why it happens, and not only a working solution.
Thank you :)
In this call
swapArray(a,b);
the argument expressions have the type int * while the function parameters have the type int **. There is no implicit conversion from the type int * to the type int **. So the compiler shall issue a diagnostic message.
In any case the swap function as it is implemented does not make sense. Your program has undefined behavior at least because it tries to swap pointers instead of the arrays themselves.
Take into account that arrays are not pointers though in expressions with rare exceptions they indeed are implicitly converted to pointers to their first elements.
To swap elements of two arrays you have to swap each pair of elemenets separatly.
And you have to supply the number of elements in the arrays. Otherwise the arrays need to have a sentinel value.
Here is a demonstrative program that shows how the function swap can be defined.
#include <stdio.h>
void printArr( const int a[], size_t n, const char *s )
{
printf( "%s:\t", s );
for ( size_t i = 0; i < n; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
}
void swapArray( int *a, int *b, size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
int tmp = a[i];
a[i] = b[i];
b[i] = tmp;
}
}
int main(void)
{
enum { N = 4 };
int a[N] = { 1, 2, 3, 4 };
int b[N] = { 5, 6, 7, 8 };
printArr( a, N, "a" );
printArr( b, N, "b" );
putchar( '\n' );
swapArray( a, b, N );
printArr( a, N, "a" );
printArr( b, N, "b" );
putchar( '\n' );
return 0;
}
Its output is
a: 1 2 3 4
b: 5 6 7 8
a: 5 6 7 8
b: 1 2 3 4
You could swap visual representations of original arrays using pointers. But in this case the arrays themselves will not be swapped.
Consider the following program.
#include <stdio.h>
void printArr( const int a[], size_t n, const char *s )
{
printf( "%s:\t", s );
for ( size_t i = 0; i < n; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
}
void swapArray( int **a, int **b )
{
int *tmp = *a;
*a = *b;
*b = tmp;
}
int main(void)
{
enum { N = 4 };
int a[N] = { 1, 2, 3, 4 };
int b[N] = { 5, 6, 7, 8 };
printArr( a, N, "a" );
printArr( b, N, "b" );
putchar( '\n' );
int *pa = a;
int *pb = b;
swapArray( &pa, &pb );
printArr( pa, N, "pa" );
printArr( pb, N, "pb" );
putchar( '\n' );
printArr( a, N, "a" );
printArr( b, N, "b" );
putchar( '\n' );
return 0;
}
Its output is
a: 1 2 3 4
b: 5 6 7 8
pa: 5 6 7 8
pb: 1 2 3 4
a: 1 2 3 4
b: 5 6 7 8
As you see the arrays were not swapped. However the pointers that point to first elements of the arrays were swapped. Using the pointers you can simulate swapping of arrays.
Opposite to C C++ has a template function std::swap for arrays that can be called indeed simply like
std::swap( a, b );
I guess on your platform the size of the pointer is 64 bit, and the size of an in is 32 bit.
When calling swapArray, the compiler implicitly reinterprets your arrays of int as an array of pointers. (These are pointers to int but this is irrelevant here).
swapArray then just swaps the first element of these pointer arrays.
Luckily your original int arrays are large enough so that no illegal access happens.
Since pointer is 64 bit is corresponds to two int which get swapped.
In C an array is not a single "thing" you can swap. You will need to swap it element-by-element.
The only case in which you can swap these array "things" in one time is if they are pointers to arrays.
int *a = malloc(n*sizeof(int));
int *b = malloc(n*sizeof(int));
int *tmp;
tmp=a; a=b; b=tmp;
The problem is, that I don't know the size of the arrays, and for my
understading they can even be in diffrent sizes.
Then let's do it with different sizes! But I don't want to support a "C&P behaviour" and hence I won't provide a complete program. I just provide some short cuts and explain them.
As already shown in the other answers you need to specify the size of an array x[] if you pass it to a function like e.g. swapArray().
But in your main() you are statically defining your two arrays. Let me do it this way:
int a[] = { 1, 2, 3 };
int b[] = { 5, 6, 7, 8, 9 };
Here we defined two arrays statically with different sizes. But the sizes are known. The compiler knows them at build/compile time. There's a build time operator sizeof() which returns the size of a type or a variable at compile time. Hence we can use sizeof(a) to get the size of array a.
But there's one light issue: The "unit" returned by sizeof() is bytes and not elements. Hence we must divide it by the size of the type (here: int) to get the actual number of elements in the array:
size_t size_a = sizeof(a) / sizeof(int);
(Actually this means that for e.g. size_a it will end up with 12 / 4 which will actually write a 3 as a pre-calculated value in your compiled program. I assume here that int takes up 4 bytes.)
For your swapping function you must pass the lower value of both size_a and size_b. We can simply get the minimum value with this:
size_t size_min = (size_a < size_b) ? size_a : size_b;
In case that size_a is smaller then size_a is taken. Otherwise size_b. This is calculated at run time. (If you want to do this at build time because of static values then you need to use preprocessor directives.)
Calling printArr() is straight forward, just pass the correct size:
printArr(b,"b",size_b);
And for swap we use size_min:
swapArray(a, b, size_min);
That's it for handling arrays with different sizes.
A very simple swapArray() could look like this:
void swapArray(int a[],int b[], size_t size) { // or int *a, int *b...
while (size > 0) {
size--;
int tmp = a[size];
a[size] = b[size];
b[size] = tmp;
}
}
We don't need to define an additional loop variable because we can simply use size and decrease it until it reaches 0.

how and why sizeof(a)/sizeof(a[0]) in c is used to calculate the number of elements in an array

I am a beginner to programming and i don't know the exact meaning of sizeof(a) and sizeof(a[0]) to calculate the no of elements in an array.
Why and where is this function used ?
And what is the purpose of dividing them.
According to the C Standard (6.5.3.4 The sizeof and alignof operators)
2 The sizeof operator yields the size (in bytes) of its operand, which
may be an expression or the parenthesized name of a type. The size is
determined from the type of the operand. The result is an integer. If
the type of the operand is a variable length array type, the operand
is evaluated; otherwise, the operand is not evaluated and the result
is an integer constant.
So if you have an array as for example
int a[N];
where N is some integer value then expression
sizeof( a )
yields the number of bytes occupied by the array. As the array has N elements and each element in turn occupies sizeof( int ) bytes then
sizeof( a ) == N * sizeof( int )
or what is the same
sizeof( a ) == N * sizeof( a[0] )
As result you can calculate N the following way
N = sizeof( a ) / sizeof( a[0] )
It is useful if you do not know the exact size of an array for example because its size depends on the number of initializers.
For example
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
const size_t N = sizeof( a ) / sizeof( *a );
Take into account that sometimes beginners make an error.
Let's assume that you have a function declaring an array as a parameter.
For example
void f( int a[10] );
and the function can be called like
int a[10];
f( a );
Beginners usually write in the body of the function the following expression
void f( int a[10] )
{
size_t n = sizeof( a ) / sizeof( a[0] );
//...
}
However it is a wrong code. The problem is that parameters declared like arrays are adjusted to pointers to the type of the array element. So the function declaration actually looks like
void f( int *a );
and within the function in expression
size_t n = sizeof( a ) / sizeof( a[0] );
parameter a is pointer. That is it is equivalent to
size_t n = sizeof( int * ) / sizeof( int );
Depending on the used system pointers occupy either 4 or 8 bytes. So you will get either 2 or 1 if sizeof( int ) is equal to 4.
You will not get the number of elements in the array that was used as the argument.
Pointers do not keep an information about whether they point to a single object or the first object of some array.
In this case you should declare the function with second parameter that specifies the number of elements in the array. For example
void f( int *a, size_t n );
meaning of sizeof(a) and sizeof(a[0])
sizeof(a) is the size (in bytes) of its operand, in this case, an array called a.
sizeof(a[0]) is the size (in bytes) of its operand, in this case, a single element of the array.
... to calculate the number of elements in an array.
Divide the size of the array by the size of an element. sizeof(a)/sizeof(a[0])
Why?
For easier code maintenance. Consider using
some_type a[N];
... code that visually separates the declaration and the below loop
for (i=0; i<N; i++)
foo(a[i])
versus
some_type a[N];
... lots of code
for (i=0; i<sizeof(a)/sizeof(a[0]); i++)
foo(a[i])
With the first method, after an update of some_type a[N]; to some_type a[N+1];, we need to search through code to also update the loop and other places that may need adjustment.
With the second method, after an update of some_type a[N]; to some_type a[N+1];, we are done.
sizeof returns the size of a variable in bytes. because of that, sizeof(a) where a is an array will return the size of the array, witch is the number of elements in the array times the size of one element.
sizeof(a[0]) will give you the size of one element in the array (we just chose the first).
so - sizeof(a) / sizeof(a[0]) = length of array * size of one element in the array / size of one element in the array = length of array.
in addition to what was said,
the fact that sizeof( myarray ) works and returns the type multiplied by the number of elements I believe can be very compiler dependent. Some compilers will allow you to do this, others will not.
This is one of the gotchya's in C programming if you are not careful.
Try compiling and running this program to see for yourself.
# include <stdio.h>
# include <stdlib.h>
void Z1 ( int *z )
{
printf(" size of z1 = %d\n", sizeof( z ) );
}
void Z2 ( int z[] )
{
printf(" size of z2 = %d\n", sizeof( z ) );
}
void Z3 ( int z[10] )
{
printf(" size of z3 = %d\n", sizeof( z ) );
printf(" size of z3[5] = %d\n", sizeof ( z[5] ) );
}
int main ( int argc, char *argv[] )
{
char a1;
short int a2;
int a3;
long int a4;
float a5;
double a6;
int myarray[10];
for ( a3 = 0; a3 < 10; a3++ )
{
myarray[a3] = a3;
}
printf("\n");
printf(" size of char = %d\n", sizeof( a1 ) );
printf(" size of short int = %d\n", sizeof( a2 ) );
printf(" size of int = %d\n", sizeof( a3 ) );
printf(" size of long int = %d\n", sizeof( a4 ) );
printf(" size of float = %d\n", sizeof( a5 ) );
printf(" size of double = %d\n", sizeof( a6 ) );
printf(" size of myarray = %d\n", sizeof( myarray ) );
printf(" size of myarray[5] = %d\n", sizeof( myarray[5] ) );
printf("\n");
Z1( myarray );
Z2( myarray );
Z3( myarray );
}
compiled in linux x86-64 using gcc version 4.3.4,
the output i got was
size of char = 1
size of short int = 2
size of int = 4
size of long int = 8
size of float = 4
size of double = 8
size of myarray = 40
size of myarray[5] = 4
size of z1 = 8
size of z2 = 8
size of z3 = 8
size of z3[5] = 4
I will try to explain in simple words:
Look if we know size of 1 element is 4 and total size of array is 20 then how many number of elements are their in array.
4 * X = 20
X = 20/4
Here also, we are doing same thing
number of elements in array =
sizeof(Array) / sizeof 1 element of Array(sizeof(A[0]))

Passing multidimensional arrays as function arguments in C

In C can I pass a multidimensional array to a function as a single argument when I don't know what the dimensions of the array are going to be?
Besides, my multidimensional array may contain types other than strings.
Pass an explicit pointer to the first element with the array dimensions as separate parameters. For example, to handle arbitrarily sized 2-d arrays of int:
void func_2d(int *p, size_t M, size_t N)
{
size_t i, j;
...
p[i*N+j] = ...;
}
which would be called as
...
int arr1[10][20];
int arr2[5][80];
...
func_2d(&arr1[0][0], 10, 20);
func_2d(&arr2[0][0], 5, 80);
Same principle applies for higher-dimension arrays:
func_3d(int *p, size_t X, size_t Y, size_t Z)
{
size_t i, j, k;
...
p[i*Y*Z+j*Z+k] = ...;
...
}
...
arr2[10][20][30];
...
func_3d(&arr[0][0][0], 10, 20, 30);
You can declare your function as:
f(int size, int data[][size]) {...}
The compiler will then do all pointer arithmetic for you.
Note that the dimensions sizes must appear before the array itself.
GNU C allows for argument declaration forwarding (in case you really need to pass dimensions after the array):
f(int size; int data[][size], int size) {...}
The first dimension, although you can pass as argument too, is useless for the C compiler (even for sizeof operator, when applied over array passed as argument will always treat is as a pointer to first element).
You can do this with any data type. Simply make it a pointer-to-pointer:
typedef struct {
int myint;
char* mystring;
} data;
data** array;
But don't forget you still have to malloc the variable, and it does get a bit complex:
//initialize
int x,y,w,h;
w = 10; //width of array
h = 20; //height of array
//malloc the 'y' dimension
array = malloc(sizeof(data*) * h);
//iterate over 'y' dimension
for(y=0;y<h;y++){
//malloc the 'x' dimension
array[y] = malloc(sizeof(data) * w);
//iterate over the 'x' dimension
for(x=0;x<w;x++){
//malloc the string in the data structure
array[y][x].mystring = malloc(50); //50 chars
//initialize
array[y][x].myint = 6;
strcpy(array[y][x].mystring, "w00t");
}
}
The code to deallocate the structure looks similar - don't forget to call free() on everything you malloced! (Also, in robust applications you should check the return of malloc().)
Now let's say you want to pass this to a function. You can still use the double pointer, because you probably want to do manipulations on the data structure, not the pointer to pointers of data structures:
int whatsMyInt(data** arrayPtr, int x, int y){
return arrayPtr[y][x].myint;
}
Call this function with:
printf("My int is %d.\n", whatsMyInt(array, 2, 4));
Output:
My int is 6.
In C can I pass a multidimensional array to a function as a single argument when I don't know what the dimensions of the array are going to be?
No
If by "single argument" you mean passing just the array without passing the array dimensions, no you can't. At least not for true multidimensional arrays.
You can put the dimension[s] into a structure along with the array and claim you're passing a "single argument", but that's really just packing multiple values into a single container and calling that container "one argument".
You can pass an array of known type and number of dimensions but unknown size by passing the dimensions themselves and the array like this:
void print2dIntArray( size_t x, size_t y, int array[ x ][ y ] )
{
for ( size_t ii = 0, ii < x; ii++ )
{
char *sep = "";
for ( size_t jj = 0; jj < y; jj++ )
{
printf( "%s%d", sep, array[ ii ][ jj ] );
sep = ", ";
}
printf( "\n" );
}
}
You would call that function like this:
int a[ 4 ][ 5 ];
int b[ 255 ][ 16 ];
...
print2dIntArray( 4, 5, a );
....
printt2dIntArray( 255, 16, b );
Similarly, a 3-dimensional array of, for example, a struct pixel:
void print3dPixelArray( size_t x, size_t y, size_t z, struct pixel pixelArray[ x ][ y ][ z ] )
{
...
}
or a 1-dimensional double array:
void print1dDoubleArray( size_t x, double doubleArray[ x ] )
{
...
}
BUT...
However, it can be possible to pass "arrays of pointers to arrays of pointers to ... an array of type X" constructs that are often mislabeled as a "multidimensional array" as a single argument as long as the base type X has an sentinel value that can be used to indicate the end of the final, lowest-level single-dimensional array of type X.
For example, the char **argv value passed to main() is a pointer to an array of pointers to char. The initial array of char * pointers ends with a NULL sentinel value, while each char array referenced by the array of char * pointers ends with a NUL character value of '\0'.
For example, if you can use NAN as a sentinel value because actual data won't ever be a NAN, you could print a double ** like this:
void printDoubles( double **notAnArray )
{
while ( *notAnArray )
{
char *sep = "";
for ( size_t ii = 0; ( *notAnArray )[ ii ] != NAN; ii++ )
{
printf( "%s%f", sep, ( *notAnArray )[ ii ] );
sep = ", ";
}
notAnArray++;
}
}
int matmax(int **p, int dim) // p- matrix , dim- dimension of the matrix
{
return p[0][0];
}
int main()
{
int *u[5]; // will be a 5x5 matrix
for(int i = 0; i < 5; i++)
u[i] = new int[5];
u[0][0] = 1; // initialize u[0][0] - not mandatory
// put data in u[][]
printf("%d", matmax(u, 0)); //call to function
getche(); // just to see the result
}

Resources