Printing value of a pointer to a pointer - c

I am trying to wrap my head around "pointer to a pointer". And I tried some experiments and I got stuck here for a while:
int array[5] = {4 , 5 ,6 ,7 ,8};
int *p = array;
int **pp = &p;
for ( int i = 0; i < 4; i ++)
{
printf("\nprinting\n");
printf("Source: %d\n", array[i]);
printf("Output by pointer: %d, %d\n", p[i], *(p + i));
printf("Output by pointer to a pointer: %d, %d\n", *pp[i], **(pp + i) );
}
And I got this as output:
printing
Source: 4
Output by pointer: 4, 4
Output by pointer to a pointer: 4, 4
printing
Source: 5
Output by pointer: 5, 5
I don't understand why after 1 loop, the program stop at the 2nd loop- line 9. Did I misunderstand anything basic knowledge or something else.
Thank you for reading.

Change the last printf to:
printf("Output by pointer to a pointer: %d, %d\n", (*pp)[i], *(*pp + i) );
You're basically using *pp in place of p, but the * operator doesn't group as tightly as [] so you need to use parentheses in the first form. In the second form, you need to dereference pp before adding i, after which the result is dereferenced.

For starters it is unclear why there is used the magic number 4 in the loop instead of the number 5 that is the number of elements in the array
for ( int i = 0; i < 4; i ++)
^^^^^
The pointer pp does not point to first element of an array. It points to a single object
int **pp = &p;
So these expressions
*pp[i] (that is equivalent to *(pp[i] )
and
**(pp + i)
does not make sense.
An expression using the pointer p can be written using the pointer pp like *pp.
So these correct expressions
p[i]
and
*(p + i)
can be written using the pointer pp the following way (just substitute p for *pp taking into account operation precedences)
( *pp )[i]
and
*( *pp + i )

You acesses to pointer thru pointer-to-pointers are wrong:
you must access the pointee as the array:
int array[5] = {4 , 5 ,6 ,7 ,8};
int *p = array;
int **pp = &p;
for ( int i = 0; i < 4; i ++)
{
printf("\nprinting\n");
printf("Source: %d\n", array[i]);
printf("Output by pointer: %d, %d\n", p[i], *(p + i));
printf("Output by pointer to a pointer: %d, %d\n", (*pp)[i], *(*pp + i) );
}

This line is wrong
printf("Output by pointer to a pointer: %d, %d\n", *pp[i], **(pp + i) );
You need to change it to
printf("Output by pointer to a pointer: %d, %d\n", (*pp)[i], *(*pp + i) );
so that you dereference the double pointer before using it as a normal pointer.
You can think of it like this:
p is the same as (*pp)
In other words - in a valid expression that uses p you are allowed to substitute p with (*pp). That is
p[i] --> (*p)[i]
*(p + i) --> *((*pp) + i) --> *(*pp + i)
Notice that the parenthesis is important. The parenthesis can be removed in the second example but not in the first as [] has higher precedence than *.
Doing pp + i generates a pointer that doesn't point to any valid object. So when you dereference it using **(pp + i) you do an illegal access an your program crashes.

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.

Understanding double pointer to an array in C

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

Use of &ampersand and square bracket in printf

I came across the following code in an MCQ quiz,
#include <stdio.h>
int main()
{
int j =2, k =4;
printf(&j["Programming"], &k["Theory"]);
k = j ^ 3;
if (k == j)
printf(&k["Practical"], "Trytosolve");
else
printf(&j["Problem creation"]);
return 0;
}
where ampersand is used in the beginning itself and outside the quotes ("") of printf statement. I am only aware of the traditional use of printf statement and its format specifiers.
I tried to run this code, and it showed no error but this warning:
format not a string literal and no format arguments
and the following output
ogrammingoblem creation (this was one of the options in multiple choices)
I tried to search for such use, but could not find. Can someone explain this use of & and square brackets?
Say we have an array a and a variable i of integral type, then a[i] is equivalent to *(a + i), i.e. we can obtain the ith element of a by decaying a into a pointer to its first element, incrementing that pointer by i and dereferencing the result. This it true because arrays occupy contiguous addresses in memory.
Now, as it turns out, i[a] is also equivalent to a[i], this is more of a "trick" that nobody (to my knowledge) would ever use in production. It's sort of intuitively justifiable that this would be the case because a[i] == *(a + i) == *(i + a) == i[a].
So then, &j["Programming"] == &(*(j + "Programming")). And because dereferencing a pointer and then taking it's address is a noop, this is j + "Programming" == "Programming" + j == "ogramming", because strings are just arrays of characters.
Same for the other branch, which is executed because 2 ^ 3 == 1 != 2.
Maybe this example program will show you the math behind the scenes:
#include <stdio.h>
int main(void)
{
int j=2, k=4;
char *p1 = "Programming";
// Print the address of j
printf("&j = %p\n", &j);
printf("\n");
printf("Pointer arithmetic\n");
// Print the address of "Programming"
printf("p1 = %p\n", p1);
// Print the value of j
printf("j = %8d\n", j);
// Print the result of the pointer computation
printf("&j[\"%s\"] = %p\n", p1, &j[p1]);
// Print the result of the equivalent pointer computation
printf("p1 + j = %p\n", p1 + j);
printf("\n");
printf("Print strings\n");
// Print "Programming" after skipping the first two letters
printf("&j[\"%s\"] = %s\n", p1, &j[p1]);
// Print "Programming" after skipping the first two letters
printf("p1 + j = %s\n", p1 + j);
return 0;
}
Output
&j = 0x7fffb3325aa8
Pointer arithmetic
p1 = 0x4006e4
j = 2
&j["Programming"] = 0x4006e6
p1 + j = 0x4006e6
Print strings
&j["Programming"] = ogramming
p1 + j = ogramming

Why does the address of a pointer var change in this scenario?

So, I'm following "Let Us C" book, and they have an example for pointers, can you explain why the value of i and j change values in this scenario?:
main( )
{
int i = 3, *j, **k ;
j = &i ;
k = &j ;
printf ( "\nAddress of i = %u", *k ) ;
printf ( "\nAddress of j = %u", &j ) ;
}
Output
Address of i = 65524 Address of j = 65522
I understand in C that new variable declarations for example int i =3; int k=5 are assigned different memory locations by C, just cant seem to wrap my head around why this is outputting different values?
You are expecting *k (Same as address of i) and &j (address of j) to be same. They are different type int * v/s int ** and different values.
Never use %u to print addresses rather use:
printf ( "\nAddress of i = %p", (void *)*k ) ;
On the other hand, if you compare &j and k, those should be same.
For example:
printf ( "%p v/s %p\n", (void *)&j, (void *)k);
Because you are printing the pointer to k in the first printf statement, not the actual value of k. k holds the value of j's reference, so if you wanted the two statements to be equal, just print k.
Point 1: use %p to print the address. Also, cast the corresponding argument to (void *)
Point 2: *k (type int *) and &j (type int **) are two different things. Maybe you wanted to print either of
k and &j (both int **)
*k and j (both int *)
printf ( "\nAddress of i = %u", *k );
Here *k prints the value stored at j not the address of j.
To get the address of j, you need to print k without de-referencing it.
Assume that your variables are stored in following location.
Note: Addresses are just an assumption.
Now *k means de-reference the value stored at k (ie) value stored at memory location 200.
Value stored at 200 is 100 which is the address of i,not the address of j.
When your program start, the OS kernel decides, based on many criteria, where to put your program and how to map it into memory.
So, when you start it several time in a row, the memory location may or may not change.
This is why you can't hard-code absolute memory location in your program, you always pick a start point how know (for instance, the first element of an array) and navigate in your memory from here.
when your program starts, each variable gets a place in memory:
int i = 3, *j, **k ;
in your case, we know these adresses got decided:
address of (int i) = 65524
address of (int* j) = 65522
address of (int** k) = unknown
the operator & gets the adress of the variable, so you get the output you observe.
Given the code
int i = 3, *j, **k ;
j = &i ;
k = &j ;
then the following are true:
**k == *j == i == 3
*k == j == &i
k == &j
That is, the expressions **k, *j, and i all have type int and evaluate to 3, the expressions *k, j, and &i all have type int * and evaluate to the address of i, and the expressions k and &j have type int ** and evaluate to the address of j.
So,
printf( "value of i = %d\n", i );
printf( "value of i (through j) = %d\n", *j );
printf( "value of i (through k) = %d\n", **k );
printf( "address of i = %p\n", (void *) &i );
printf( "address of i (through j) = %p\n", (void *) j );
printf( "address of i (through k) = %p\n", (void *) *k );
printf( "address of j = %p\n", (void *) &j );
printf( "address of j (through k) = %p\n", k );
printf( "address of k = %p\n", (void *) &k );
Use the %p conversion specifier to print pointer values. It expects a void * as its corresponding argument, and this is one of the few places (probably the only place) in C where you need to explicitly cast a pointer value to void *.

In which precedence is this statement evaluated?

++*P--;
That is a question from an exam, if P a pointer to any element in an array, explain what this statement really does.
I even wrote a simple code to evaluate it:
int i;
int* array = calloc(10, sizeof(int));
for (i = 0; i < 10; i++) {
array[i] = i;
printf("%d,", array[i]);
}
int* P = array + 5;
printf("\n %p", P);
printf("\n %d", *P);
++*P--;
printf("\n %p", P);
printf("\n %d \n", *P);
for (i = 0; i < 10; i++) {
printf("%d,", array[i]);
}
But the output confuses me even more:
0,1,2,3,4,5,6,7,8,9,
0x100105534
5
0x100105530
4
0,1,2,3,4,6,6,7,8,9,
It looks like it first dereferences P, then increases its value and then decreases value of pointer P, but why?
According to K&R table 2-1 from p53 (see the picture below)
++, --, and * (dereference) has the same precedence and associativity from right to left.
So first step should be decreasing value of P, then dereference and then increasing dereferenced value, am I wrong?
You are correct that the precedence is
++(*(P--))
But note that the decrement is a postfix operation: even though the change to P happens first, the rest of the expression uses the old value of P. So in your example, first P is decremented to array+4, but the value of P-- is array+5, so array[5] gets incremented.
You can imagine this expression
++*P--
the following way
int *tmp = p;
--p;
int value = *tmp;
++value;
Here is a demonstrative program
#include <stdio.h>
int main( void )
{
char s[] = "Hello World";
char *p = s + 6;
std::printf( "%c\n", ++*p-- );
std::printf( "%s\n", s );
p = s + 6;
char *tmp = p--;
char value = *tmp;
++value;
std::printf( "%c\n", value );
std::printf( "%s\n", s );
}
The program output is
X
Hello Xorld
Y
Hello Xorld
The difference in the outputting the string is that expression ++*p-- changes the string itself but expression ++value; changes a separate object. But the logic is similar.
Postfix expression p-- has the highest priority but its value is the value of p before decreasing.
Unary operators ++ and * in expression ++*p-- group right to left. So at first operator * is applied to the expression and after that operator ++ is applied.

Resources