0

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.

15
  • 3
    "I know that the code is producing a lot of warnings" is like saying "sure the house is on fire, but I want to know why the lights are flickering." You've got undefined behaviour. Commented Mar 30, 2021 at 3:33
  • 1
    At int (**p)[2] = &a; it goes off the rails. Everything after that is pure nonsense. You have an array of int[2][2], not an array of int*. Interpreting integers as actual pointers is asking for trouble. Commented Mar 30, 2021 at 3:34
  • 1
    @tadman Okay I got it. Thank you so much for helping me. Commented Mar 30, 2021 at 3:54
  • 1
    It'd be helpful if you told us where you found this question in the form of a questionable program. Was it in a book? On a web page? What does the book or page say about the program? Commented Mar 30, 2021 at 3:55
  • 1
    The core idea is this. If the code produces warnings, don't run it. Commented Mar 30, 2021 at 6:07

4 Answers 4

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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(""); } 

Comments

0

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] 

Comments

-1

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 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.