Understanding double pointer to an array in C - arrays

I have been learning C for couple of months and I came across a question which is given below.
#include <stdio.h>
int main() {
int a[2][2] = {{1,2}, {3,4}};
int (**p)[2] = &a;
for (int i=0; i<2; ++i) {
for (int j=0; j<2; ++j) {
printf("%d %u\n", a[i][j], (*(a+i) + j));
}
}
for (int i=0; i<4; ++i) {
printf("%d %u\n", *(*p + i), (*p + i));
}
printf("%u\n", p);
printf("%u\n", p+1);
printf("%u\n", p+2);
printf("%u\n", p+3);
printf("%u\n", *p);
printf("%u\n", *p+1);
printf("%u\n", *p+2);
printf("%u\n", *p+3);
puts("");
}
The output that I am getting on my machine is as follows:
1 3751802992
2 3751802996
3 3751803000
4 3751803004
1 1
9 9
17 17
25 25
3751802992
3751803000
3751803008
3751803016
1
9
17
25
I understand the first four lines of the output where the elements of the 2D array and their respective addresses is getting printed but I have absolutely no clue how the other outputs are happening.
I checked in an online IDE and there also I am getting the same output except the addresses which obviously will differ.
I know that int (**p)[2] is incomparable pointer type to a[2][2] which is a (int *)[2] data type.
But still I want to understand how the p pointer is working.
Can someone please help me understand how this is happening?
I have been eagerly waiting to get the logic behind the code outputs.
I am extremely sorry for the long code snippet and the long output sequence.
Thanks in advance.
N.B - I know that the code is producing a lot of warnings but I want to get the core idea about p.

The problem with this code starts right here:
int main() {
int a[2][2] = {{1,2}, {3,4}};
int (**p)[2] = &a; // <-- Invalid conversion, undefined behaviour
// warning: incompatible pointer types initializing 'int (**)[2]' with an expression of type 'int (*)[2][2]' [-Wincompatible-pointer-types]
// ... Everything past here is undefined behaviour
}
There's a huge difference between int** and what you're attempting to cast, one big enough that this conversion isn't possible.
int** means, specifically, a structure where it's an array of int*, or pointers. Treating int[2] as a pointer is going to be a mess. That any of this code even semi-works is hard to explain. It's the compiler trying to make the best of a bad situation.

I introduced a macro LEN to calculate your array sizes instead of hard-coping the magic numbers, fixed the declaration of p, changed the unsigned format %u to signed %d as you were printed signed values, the last loop, I am sure what the 2nd thing you were trying to print so left it out, and the last section of print statements were pointers so used %p for those in a loop instead of duplicating the code:
#include <stdio.h>
#define LEN(a) sizeof(a) / sizeof(*a)
int main() {
int a[2][2] = {{1,2}, {3,4}};
int (*p)[2] = a;
for (int i=0; i < LEN(a); i++) {
for (int j = 0; j < LEN(*a); j++) {
printf("%d %d\n", a[i][j], *(*(a + i) + j));
}
}
for (int i=0; i < LEN(a) * LEN(*a); i++) {
printf("%d\n", *(*p + i));
}
for(int i = 0; i < LEN(a) * LEN(*a); i++) {
printf("%p\n", p + i);
}
for(int i = 0; i < LEN(a) * LEN(*a); i++) {
printf("%p\n", (void *) *(p + i));
}
puts("");
}

This is a problem:
int (**p)[2] = &a; // int (**)[2] = int (*)[2][2]
The type of &a is int (*)[2][2], not int (**)[2]. Your pointer declaration should be
int (*p)[2][2] = &a;
Unless it is the operand of the sizeof or unary & operators or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T will be converted, or "decay", to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array.
The expression a "decays" from type "2-element array of 2-element array of int" (int [2][2]) to "pointer to 2-element array of int" (int (*)[2]). However, since a is the operand of the unary & operator that conversion doesn’t take place, so &a has type "pointer to 2-element array of 2-element array of int" (int (*)[2][2]). Thus,
p == &a
(*p) == a
(*p) + i == a + i == &(*p)[i] == &a[i]
*((*p) + i) == *(a + i) == (*p)[i] == a[i]
*((*p) + i) + j == *(a + i) + j == &(*p)[i][j] == &a[i][j]
*(*((*p) + i) + j) == *(*(a + i) + j) == (*p)[i][j] == a[i][j]

A pointer is used to store the address of variables. So, when we define a pointer to pointer, the first pointer is used to store the address of the second pointer. Thus it is known as double pointers.
EXAMPLE:
int main() {
int integerValue = 84;
int *pointer1;
int **pointer2;
pointer1 = &integerValue;
pointer2= &pointer1;
printf("Value of integer = %d\n", integerValue);
printf("Value of integer using single pointer = %d\n", *pointer1);
printf("Value of integer using double pointer = %d\n", **pointer2);
return 0;
}
OUTPUT:
Value of integer = 84
Value of integer using single pointer = 84
Value of integer using double pointer = 84

Related

Pointers to an Array In C

So my book is explaining me pointers to an array using ts example
#include <stdio.h>
int main()
{
int s[4][2] = {
{1234,56},{1212,33},{1434,80},{1312,78}
};
int(*p)[2];
int i, j, * pint;
for (i = 0; i <= 3; i++)
{
p = &s[i];
pint = (int*)p;
printf("\n");
for (j = 0; j<= 1; j++)
{
printf("%d ", *(pint + j));
}
}
return 0;
}
The output is Given as
1234 56
1212 33
1434 80
1312 78
No issue I am getting the same output.
My question is what was the need of using another pointer pint ?
Why can't we directly use P?
So When I tried to do it using P directly it didn't work
printf("%d ", *(p + j));
I got garbage values in output, Why is this happening?
I also tried printing p and pint they are the same.
Although p and pint have the same value, p + 1 and pint + 1 do not. p + 1 is the same as (char *)p + sizeof *p, and pint + 1 is the same as (char *)pint + sizeof *pint. Since the size of the object pointed to is different, the arithmetic gives different results.
The pointer p is declared like
int(*p)[2];
So dereferencing the pointer expression with the pointer in this call of printf
printf("%d ", *(p + j));
you will get the j-th "row" of the type int[2] of the two dimensional array that in turn will be implicitly converted to a pointer of the type int * that will point to the first element of the j-th "row".
So instead of outputting elements of each row you will output first elements of each row that moreover results in undefined behavior when i will be greater than 2.

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.

How to use pointer to bidimensional array C

How do I edit a value in an array with pointer in C?
int *pointer;
int array[3][1];
I tried this:
int *Pointer
int array[2][2];
Pointer[1][1]= 6;
but when compiling, I get a segmentation fault error. What to do?
Given some array int Array[Rows][Columns], to make a pointer to a specific element Array[r][c] in it, define int *Pointer = &Array[r][c];.
Then you may access that element using *Pointer in an expression, including assigning to *Pointer to assign values to that element. You may also refer to the element as Pointer[0], and you may refer to other elements in the same row as Pointer[y], where y is such that 0 ≤ y+c < Columns, i.e., Pointer[y] remains in the same row of the array.
You may also use Pointer[y] to refer to elements of the array in other rows as long as none of the language lawyers see you doing it. (In other words, this behavior is technically not defined by the C standard, but many compilers allow it.) E.g., after Pointer = &Array[r][c];, Pointer[2*Columns+3] will refer to the element Array[r+2][c+3].
To make a pointer you can use to access elements of the array using two dimensions, define int (*Pointer)[Columns] = &Array[r];.
Then Pointer[x][y] will refer to element Array[r+x][y]. In particularly, after int (*Pointer)[Columns] = &Array[0]; or int (*Pointer)[Columns] = Array;, Pointer[x][y] and Array[x][y] will refer to the same element.
You can access any given element with this syntax: array[x][y].
By the same token, you can assign your pointer to any element with this syntax: p = &array[x][y].
In C, you can often treat arrays and pointers as "equivalent". Here is a good explanation:
https://eli.thegreenplace.net/2009/10/21/are-pointers-and-arrays-equivalent-in-c
However, you cannot treat a simple pointer as a 2-d array. Here's a code example:
/*
* Sample output:
*
* array=0x7ffc463d0860
* 1 2 3
* 4 5 6
* 7 8 9
* p=0x7ffc463d0860
* 0x7ffc463d0864:1 0x7ffc463d0868:2 0x7ffc463d086c:3
* 0x7ffc463d0870:4 0x7ffc463d0874:5 0x7ffc463d0878:6
* 0x7ffc463d087c:7 0x7ffc463d0880:8 0x7ffc463d0884:9
*/
#include <stdio.h>
int main()
{
int i, j, *p;
int array[3][3] = {
{1,2,3},
{4,5,6},
{7,8,9}
};
// Dereference 2-D array using indexes
printf("array=%p\n", array);
for (i=0; i < 3; i++) {
for (j=0; j < 3; j++)
printf ("%d ", array[i][j]);
printf ("\n");
}
// Dereference 2-D array using pointer
p = &array[0][0];
printf("p=%p\n", p);
for (i=0; i < 3; i++) {
for (j=0; j < 3; j++)
printf ("%p:%d ", p, *p++);
printf ("\n");
}
/* Compile error: subscripted value p[0][0] is neither array nor pointer nor vector
p = &array[0][0];
printf("p=%p, p[0]=%p, p[0][0]=%p\n", p, &p[0], &p[0][0]);
*/
return 0;
}
Cast the 2D-array into 1D-array to pass it to a pointer,
And then, You are ready to access array with pointer. You can use this method to pass 2D-array to a function too.
#include <stdio.h>
int main()
{
int arr[2][2];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
arr[i][j] = (2 * i) + j;
}
}
int *Pointer = (int *)arr; // Type conversion
/*
&arr[0][0] = Pointer + 0
&arr[0][1] = Pointer + 1
&arr[1][2] = Pointer + 2
&arr[2][2] = Pointer + 3
Dereference Pointer to access variable behind the address
*(Pointer + 0) = arr[0][0]
*(Pointer + 1) = arr[0][1]
*(Pointer + 2) = arr[1][2]
*(Pointer + 3) = arr[2][2]
*/
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
printf("%d ", *(Pointer + (2 * i) + j)); // Accessing array with pointer
}
printf("\n");
}
return 0;
}
Using the function wv_matalloc from https://www.ratrabbit.nl/ratrabbit/content/sw/matalloc/introduction , you can write the following code:
#include <stdio.h>
#include "wv_matalloc.h"
int main()
{
double **matrix;
int m = 3;
int n = 4;
// allocate m*n matrix:
matrix = wv_matalloc(sizeof(double),0,2,m,n);
// example of usage:
int i,j;
for (i=0; i<m; i++)
for (j=0; j<n; j++)
matrix[i][j] = i*j;
printf("2 3: %f\n",matrix[2][3]);
}
Compile with:
cc -o main main.c wv_matalloc.c
1.
You never assigned a value to Pointer in your example. Thus, attempting to access array by Pointer invokes undefined behavior.
You need to assign Pointer by the address of the first element of array if the pointer shall be a reference:
Pointer = *array;
2.
You can't use 2D notation (p[1][1]) for a pointer to int. This is a C syntax violation.
3.
Since rows of static 2D arrays are allocated subsequent in memory, you also can count the number of array elements until the specific element of desire. You need to subtract the count by 1 since indexing start at 0, not 1.
How does it work?
Each row of array contains 2 elements. a[1][1] (the first element of the second row) is directly stored after the first two.
Note: This is not the best approach. But worth a note beside all other answers as possible solution.
#include <stdio.h>
int main (void)
{
int *Pointer;
static int array[2][2];
Pointer = *array;
Pointer[2] = 6;
printf("array[1][1] (by pointer) = %d\n", Pointer[3]);
printf("array[1][1] (by array istelf) = %d\n", array[1][1]);
}
Output:
array[2][2] (by pointer) = 6
array[2][2] (by array istelf) = 6
Side Notes:
To address the first element of the second row by array[1][2] invokes undefined behavior. You should not use this way.
"but when compiling, I get a segmentation fault error."
Segmentation fault error do not occur at compile time. They occur at run time. It just gives you the impression because high probably your implementation immediately executes the program after compilation.

pointer arithmetic with pointer to array

I'm trying to do pointer arithmetic with a pointer to array, but I get a wrong value since I can't dereference the pointer properly.
Here is the code:
#include "stdlib.h"
#include "stdio.h"
int main()
{
int a[] = {10, 12, 34};
for (int i = 0; i < 3; ++i)
{
printf("%d", a[i]);
}
printf("\n");
int (*b)[3] = &a;
for (int i = 0; i < 3; ++i)
{
printf("%d", *(b++));
}
printf("\n");
return 0;
}
In the second for I can't get to print the correct value.
It doesn't work even if I write
printf("%d", *b[i]);
I'd like to see how to print correctly using the b++ and the b[i] syntax.
The following should work:
printf("%d\n", *( *b+i ));
// * b + i will give you each consecutive address starting at address of the first element a[0].
// The outer '*' will give you the value at that location.
instead of:
printf("%d", *(b++));
You have declared b to be a pointer to arrays of 3 integers and you have initialized it with address of a.
int (*b)[3] = &a;
In the first loop you will print the first element of a array but then you will move 3*sizeof(int) and trigger undefined behavior trying to print whatever there is.
To print it correctly:
int *b = a;
// int *b = &a[0]; // same thing
// int *b = (int*)&a; // same thing, &a[0] and &a both points to same address,
// though they are of different types: int* and int(*)[3]
// ...so incrementing they directly would be incorrect,
// but we take addresses as int*
for (int i = 0; i < 3; ++i)
{
printf("%d", (*b++));
}
gcc will complain about the formatting in the second for loop: it will tell you format specifies type 'int' but the argument has type 'int *
your assignment of a to b should look like this:
int *b = a

b and *b works in argument list of my function exactly same. What is the difference then? [duplicate]

This question already has answers here:
Why is the same value output for A[0], &A, and *A?
(4 answers)
Closed 9 years ago.
I use swapCardsRandomly(b) but when I tried swapCardsRandomly(*b) program still works without any problem.
What is the difference then?
/*
*shuffles cards randomly
*/
void shuffle( int b[][13] ) {
int counter;
int rand1 = rand() % 4;
int rand2 = rand() % 13;
b[rand1][rand2] = 1;
counter = 2;
while ( counter < 53 )
{
rand1 = rand() % 4;
rand2 = rand() % 13;
while ( b[rand1][rand2] != 0 )
{
rand1 = rand() % 4;
rand2 = rand() % 13;
}
b[rand1][rand2] = counter++;
}
swapCardsRandomly( b );
}
//for better shuffling swap elements randomly
void swapCardsRandomly( int m[][13] ) {
int temp;
int rand1;
int rand2;
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 13; j++ )
{
rand1 = rand() % 4;
rand2 = rand() % 13;
temp = m[i][j];
m[i][j] = m[rand1][rand2];
m[rand1][rand2] = temp;
}
}
}
Both b and *b have the same address (b[0][0]), check this:
int b[1][13];
printf("%p %p %p\n", (void *)b, (void *)*b, (void *)&(b[0][0]));
But there is a pointer type conflict with *b
demo.c:52:1: warning: passing argument 1 of ‘swapCardsRandomly’ from incompatible pointer type [enabled by default]
demo.c:9:7: note: expected ‘int (*)[13]’ but argument is of type ‘int *’
In a multi-dimensional array the first element, and a pointer to the first row have the same address. This is because the first element of an array has the same address as the array. So, in your case, b points to the first element of an int [][13] array and *b points to the first element of a int [13] array that happens to be the first row of an int [][13] array.
The next question is why it lets you pass *b to SwapCardsRandomly when it expects int [][13] as an argument. The answer is that arrays, including multi-dimensional arrays, are not proper types in C, so when passed in this manner it treats them as a way to interpret a pointer.
This is because value-wise both *b and b are equal that is (void*)b == (void*)(*b) == true.
b is a two-dimentational matrix =b[rand1][rand2]=1;
type of matrix name b is int[][13] that decays into address of first element that is 0th row in two dimensional array. (you can think a two dimensional array as array of one dimensional arrays).
Because b is address of 0th row, so *b decays into address of b[0][0] that is address of 0th element of 0th-row. Interesting is value (magnitude) wise both are equal that is why your code works. When your call your function with *b or b argument, address value auto typecasted into proper type int [][13].
To observe it, in your code try this printf-statement:
printf("\n %p %p\n", b, *b);
You will find both are equal!
To understand it more better with a diagram read this: A[0], &A, *A linked answer.
Because both of b and *b are equal in value but are of different types i.e both of these pointer expression are of different types but points to he same memory location.
b decays to pointer to first row (0th row) and it is of type int (*)[]. *b dereferences the pointer expression b hence
*b is of type int (*)[].Since that's an array type, it decays to a pointer to the first element of the array object. So it's of type int*.
For detailed explanation, must read this answer.

Resources