1-d pointer to a 2-d array - c

#include<stdio.h>
void display(int (*p)[3],int,int);
int main()
{
int a[3][4] = {1,2,3,4,
5,6,7,8,
9,0,1,6};
display(a,3,4);
}
void display(int (*p)[3],int r,int c)
{
int i,j,*q;
for(i=0;i<r;i++)
{
q=p+i;
for(j=0;j<c;j++)
printf("%d",*(q+j));
printf("\n");
}
}
this does not work but if we write
void dis(int (*p)[4],int,int);
it works
that is if we have a pointer of array having number of columns as number of element in array

Arrays used in expressions with rare exceptions are converted to pointers to their first element.
From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
So if you have an array declared like
T a[N];
where T is some type and N is some integral expression then the array can be converted to a pointer the following way.
First of all let's rewrite the declaration the following way
T ( a[N] );
Now to get pointer just substitute the declarator in the parentheses a[N] for *p. For example
T ( a[N] );
T ( *p ) = a;
So if you have a multidimensional array like this
T a[N1][N2];
then pointer to its first element can be defined the following way
T ( a[N1] )[N2];
T ( *p )[N2] = a;
In general case you can use the rule
T a[N1][N2]...[Nn];
is equivalent to
T ( a[N1] )[N2]...[Nn];
and a pointer is defined like
T ( a[N1] )[N2]...[Nn];
T ( * p )[N2]...[Nn] = a;
In your program you have the declaration
int a[3][4] = {1,2,3,4,
5,6,7,8,
9,0,1,6};
that can be rewritten as it has been shown above like
int ( a[3] )[4] = {1,2,3,4,
5,6,7,8,
9,0,1,6};
So the pointer to the first element of the array will have the type int ( * )[4]
Thus the function shall be declared at least like
void display( int (*)[4], int, int);
Take into account that within the function
void display(int (*p)[4],int r,int c)
{
int i,j,*q;
for(i=0;i<r;i++)
{
q=p+i;
for(j=0;j<c;j++)
printf("%d",*(q+j));
printf("\n");
}
}
there is an assignment of incompatible types
q=p+i;
The expression p + i has the type int ( * )[4] while the pointer q has the type int *.
It shall be written
q = *( p + i );
In this case the expression *( p + i ) has the type int[4] that is implicitly converted to pointer of the type int *
Also according to the C Standard the function main without parameters shall be declared like
int main( void )
If to use only pointers instead of indices to access elements of the array then the function can look the following way as it is shown in the demonstrative program
#include <stdio.h>
#define COLS 4
void display( int (*)[COLS], size_t );
int main( void )
{
int a[][COLS] =
{
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 0, 1, 6 }
};
const size_t ROWS = sizeof( a ) / sizeof( *a );
display( a, ROWS);
}
void display( int (*p)[COLS], size_t rows )
{
for ( int ( *p_row )[COLS] = p; p_row != p + rows; ++p_row )
{
for ( int *p_col = *p_row; p_col != *p_row + COLS; ++p_col )
{
printf( "%d ", *p_col );
}
putchar( '\n' );
}
}
Its output is
1 2 3 4
5 6 7 8
9 0 1 6

Arrays naturally decays to pointers to their first element. That is, a will decay to a pointer to a[0], i.e. &a[0].
And what is a[0]? It's an array of four int elements. So &a[0] is a pointer to an array of four int elements, or int (*)[4].

You should write void display(int (*p)[4],int,int) exactly like that.
because when you write int a[3][4] c see this like three pointers to 3 arrays of 4 elements each.

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.

C pointer with 2D array

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

Use of typecasting in pointer to an array

int s[4][2] = {1234,56,1212,33,1434,80,1312,78} ;
int (*p)[2], i, j;
int *pint;
for(i=0;i<=3;i++)
{
p = s[i];
pint = (int*) p;
for(j=0;j<=1;j++)
{
printf("%d ",*(pint+j));
}
printf("\n");
}
Here, p is a pointer to an array of 2 integers and p contains the address of the ith 1-D array. But why are we typecasting p to pint? And using pint for the rest of our program. Why can't we use p only instead of pint?
Also, I tried taking p instead of pint, but then it is printing address of 1-D array instead of elements. Why?
For starters it would be more correctly to write
pint = *p;
instead of
pint = (int*) p;
And this expression statement
p = s[i];
is also wrong. s[i] has type int[2] that used in expressions is implicitly converted to an object of type int *. While the left side operand has type int ( * )[2]. So there is an attempt to assign a pointer of type int( * )[2] with an expression of type int *. However the types are incompatible.
You have to write either
p = &s[i];
or
p = s + i;
Of course there is no need to introduce a new pointer that to output elements of the array. However using an additional pointer you can simplify constructions.
Without introducing a new pointer the loop could look like
for ( i = 0; i < 4; i++ )
{
p = s + i;
for ( j = 0; j < 2; j++ )
{
printf( "%d ", *( *p + j ) );
}
printf( "\n" );
}
This quote from the C Standard will be helpful (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
Thus array s having type int[4][2] used in expressions except as an operand of the sizeof or & operations is converted to pointer to its first element of type int ( * )[2]
If to apply operator * to the pointer the type of the result object will be int[2] that is an array. Again in expressions it in turn is converted to pointer to its first element of type int *.
So expression *p has type int *. If it would be used in the sizeof operator then it had type int[2].
One Dimension arrays:
int a[2] ;
is equiavalent to:
int *a ;
a = malloc(sizeof(int) * 2);
Two Dimension arrays:
int a[4][2] ;
is equivalent to :
int **a ;
a = malloc(sizeof(int *)*4);
for ( i = 0 ; i < 2 ; ++i){
*(a+i) = malloc(sizeof(int)*2);
}
How can it relate to your example:
int (*p)[2];
type of p : int ** EDIT:This is wrongp is of type (*)[2]
int s[4][2] ;
type of s : int **EDIT:s is type of (*)[2] not **
type of s[i] : int *
type of s[i][j] : int
Credit goes to the commentators, thanks.

Sum of an array

I can't understand why my program only prints the first number in the array.
it seems it loops only once and then something breaks the loop. The output is 232.
#include <stdio.h>
int main( int argc, char* argv[]){
int sum_arr(int arr[]);
int arr[5]={232,44,3,4,5};
printf("%d\n",sum_arr(arr));
return 0;
}
sum_arr(int arr[]){
int i,sum=0,sizeofarr=sizeof(arr)/sizeof(arr[0]);
for(i=0;i<=(sizeofarr-1);i++){
sum+=arr[i];
}
return (sum);
}
sizeofarr = sizeof(arr) / sizeof(arr[0]);
This trick to calculate the size of an array doesn't work. Because in the function, arr decays to a pointer, not an array.
To fix the problem, pass the size explicitly.
Change the code the following way
#include <stdio.h>
nt main( int argc, char* argv[])
{
int sum_arr( int arr[], size_t n );
int arr[5] = { 232, 44, 3, 4, 5 };
printf( "%d\n", sum_arr( arr, sizeof( arr ) / sizeof( *arr ) ) );
return 0;
}
int sum_arr( int arr[], size_t n )
{
int i = 0, sum = 0;
for ( ; i < n ;i++ )
{
sum += arr[i];
}
return ( sum );
}
The problem with your code is that an arrray passed as an argument is implicitly converted to a pointer to its first element. So inside function sum_array you used sizeof( int * ) / sizeof( int ) that for your system is equal to 1.
Take into account this quote from the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
Remember, in C when pass an array as an argument to a function, actually you're passing a pointer to an array.
Since the size of a pointer and an int is 4 or 8, you'll be getting sizeof(int *)/sizeof int (4/4=1 for 32-bit machines and 8/4=2 for 64-bit ones) which is 1 or 2.
In conclusion, array names in a C program are (in most cases) converted to pointers.One exception is when we use the sizeof operator on an array. If arr was converted to a pointer in this contest, sizeof(arr) would give the size of a pointer and not of the actual array, which would be rather useless, so in that case a means the array itself.
In my program the array passed in the function is converted to a pointer. Then, sizeof(arr) in the sum_arr function gives the size of a pointer and not of the actual array.
This program should be execute in this way:
#include <stdio.h>
#define SIZEOFARR(arr) (sizeof(arr)/sizeof(arr[0]))
int main(){
int sum_arr(int arr[],int size);
int arr[5]={232,44,3,4,5};
printf("The sum of the array is: %d\n",sum_arr(arr,SIZEOFARR(arr)));
return 0;
}
int sum_arr(int arr[],int size){
int i,sum=0;
for(i=0;i<size;i++){
sum+=arr[i];
}
return (sum);
}

Resources