I am confused how to understand this code. contains double pointers - c

I don't understand why the code below changes the array b:
int a[] = { 3, 6, 9 };
int b[] = { 2, 4, 6, 8, 10 };
int **c;
int **d[2];
c = (int **)malloc (b[1] * sizeof(int *));
*c = &a[1];
c[1] = c[0] + 1;
*d = c;
c = c + 2;
*c = b;
c[1] = &c[0][3];
*(d + 1) = c;
d[0][3][1] = d[1][0][0];
d[1][0][2] = d[0][1][0];
I have run this code and found the values of array a and array b but I am unable to understand how these values come.
Array a remains unchanged while b becomes 2, 4, 9, 8, 2. How does this happen?
c = (int**)malloc(b[1] * sizeof(int*)); //int **c[4] ???
c is an array of double pointers *c = &a[1] this means that c[0] has the address of array a's second index. I am not getting the way to interpret this.

The code contains actual statements, therefore it must be part of a function body, hence all declarations herein have automatic storage. It is highly convoluted, with purposely contrived double indirections... Lets analyse it one line at a time:
int a[] = { 3, 6, 9 }; -- a is an array of 3 ints initialized with some explicit values.
int b[] = { 2, 4, 6, 8, 10 }; -- likewise, b is an array of 3 ints initialized with some explicit values.
int **c; -- c is an uninitialized pointer to a pointer to int, that can be made to point to an array of pointers to int.
int **d[2]; -- d is an uninitialized array of 2 pointers to pointers to int, each of which can be made to point to an array of pointers to int.
c = (int **)malloc(b[1] * sizeof(int *)); -- c is set to point to a block of uninitialized memory with a size of 4 pointers to int. In short, c now points to an uninitialized array of 4 pointers to int.
*c = &a[1]; -- The element pointed to by c (aka A[0]) is set to point to the second element of a (aka a[1], with a value of 6). The value of A[0] is &a[1].
c[1] = c[0] + 1; -- The second element in the array pointed to by c (aka A[1]) is set to point to the element after the one pointed to by c[0], hence it points to the third element of a (aka a[2] with a value of 9). The value of A[1] is&a[2]`.
*d = c; -- The first element of d is set to the value of pointer c, which is the address of A[0]. The value of d[0] is &A[0].
c = c + 2; -- The pointer c is incremented by 2, it now points to the third element of the array A allocated with malloc(), A[2].
*c = b; -- The element pointed to by c, A[2], which is itself a pointer, is set to point to the first element of b, b[0]. The value of A[2] is &b[0].
c[1] = &c[0][3]; -- The element after that, A[3], the 4th element of the array allocated by malloc, is set to point to the 4th element of the array pointed to by the element c points to. &c[0][3] is equivalent to c[0] + 3 or &(*c)[3] or simply *c + 3. This element is b[3] which has the value 8. The value of A[3] is&b[3]`.
*(d + 1) = c; -- This is equivalent to d[1] = c; which sets the second element of d to the value of the pointer c, which is the address of the 3rd element of the array allocated wth malloc(), A[2], which points to b[0]. The value of d[1] is &A[2].
d[0][3][1] = d[1][0][0]; -- Let's rewrite these terms:
d[0][3][1] => (&A[0])[3][1] => A[3][1] => (&b[3])[1] => *((b + 3) + 1) => b[4]
d[1][0][0] => (&A[2])[0][0] => (*&A[2])[0] => A[2][0] => (&b[0])[0] => b[0] which is the value 2.
Hence b[4] = 2;.
d[1][0][2] = d[0][1][0]; -- Let's rewrite these:
d[1][0][2] => (&A[2])[0][2] => (*&A[2])[2] => A[2][2] => (&b[0])[2] => (b + 0)[2] => b[2].
d[0][1][0] => (&A[0])[1][0], ie A[1][0] => (&a[2])[0] => *&a[2] => a[2] that has a value of 9.
Hence b[2] = 9;
As a consequence, the array b now has elements { 2, 4, 9, 8, 2 }.
You can run the program:
#include <stdio.h>
#include <stdlib.h>
int main() {
int a[] = { 3, 6, 9 };
int b[] = { 2, 4, 6, 8, 10 };
int **c;
int **d[2];
c = (int **)malloc (b[1] * sizeof(int *));
*c = &a[1];
c[1] = c[0] + 1;
*d = c;
c = c + 2;
*c = b;
c[1] = &c[0][3];
*(d + 1) = c;
d[0][3][1] = d[1][0][0];
d[1][0][2] = d[0][1][0];
printf("a = { ");
for (size_t i = 0; i < sizeof a / sizeof *a; i++)
printf("%d, ", a[i]);
printf("};\n");
printf("b = { ");
for (size_t i = 0; i < sizeof b / sizeof *b; i++)
printf("%d, ", b[i]);
printf("};\n");
return 0;
}

Related

accessing C multidimensional array via array syntax vs pointer arithmetic

I'm diving into C again after a number of years. I thought that the following two print statements would have evaluated to the same output, based on other answers I have found; however it does not appear to be the case.
int main()
{
int** arr = malloc(
3 * sizeof(int*)
);
for(int y = 0; y < 3; y++) {
int* subarr = malloc(
3 * sizeof(int)
);
for(int x = 0; x < 3; x++) {
subarr[x] = y * 3 + x + 1;
}
arr[y] = subarr;
}
printf("%d\n", *(&arr[0][0]) + 3);
printf("%d\n", (&arr[0][0])[3]);
}
Could anyone explain what is going on here/what I am missing?
First of all, Let me explain what you are doing (At least for me).
arr[0] = A pointer to array {1, 2, 3}
arr[1] = A pointer to array {4, 5, 6}
arr[2] = A pointer to array {7, 8, 9}
First Case: *(&arr[0][0]) + 3
&arr[0][0] = Address of first element of {1, 2, 3}
*(&arr[0][0]) = 1 // Dereferencing the address
So, It prints 1 + 3 = 4
Second Case: (&arr[0][0])[3]
(&arr[0][0]) = Address of first element of {1, 2, 3}
But the length of array is 3, So you can only access indices up to 2.
So, It is causing undefined behaviour.

Why is p[0]++ different from *(p)++ in C

When I tried to execute these codes in C
#include <stdio.h>
int main(void)
{
int arr[] = {10, 20};
int *p = arr;
p[0]++; // *(p)++;
printf("arr[0] = %d, arr[1] = %d",arr[0], arr[1]);
return 0;
}
output: arr[0] = 11, arr[1] = 20
on replacing p[0]++; by *(p)++;
output : arr[0] = 10, arr[1] = 20
Please explain why this is. I know a[i] is equivalent to *(a + i)
The expression:
p[0]++;
basically increments the value at index 0.
While
*(p)++
Increments the pointer to the next address .
Example :
int arr = {10,20};
int *p = arr; // p points to the first element of array, i.e 10
*(p)++; // now p points to the next element i.e 20.
below code can be used:
p[0]++ means = p[0] + 1;
p[0]++ = 10 + 1;
p[0]++ = 11;
You can't do with this same thing with an array, so be careful.
I hope it helps!

Different behavior of the same two operations on pointers

I write this code and the output was like this B C D E
char a[5] = {'A' , 'B' , 'C' , 'D'};
char *b = a + 2;
int i = 0 ;
for(i = 0 ; i < 4 ; i ++)
{
*b = (a[i] + 1);
printf("%c",*b);
}
But when I add reference like this :
char a[5] = {'A' , 'B' , 'C' , 'D'};
char *b = &a + 2;
int i = 0 ;
for(i = 0 ; i < 4 ; i ++)
{
*b = (a[i] + 1);
printf("%c",*b);
}
the output become just B.
This has to do with how pointer arithmetic is done. When you add a value to a pointer, it increments the pointer by that value times the size of the type it references.
In the expression a + 2, a has type char *, so adding 2 increases the address by 2 * sizeof(char) == 2 bytes.
Given &a + 2, &a has type char (*)[5], i.e. a pointer to an array of 5 char. Adding 2 to this increases the address by 2 * sizeof(char [5]) == 10 bytes. This points to a memory location past the end of the array, so dereferencing it invokes undefined behavior, which in this cases leads to the loop exiting early.
You also have an invalid assignment in the second case, as you're trying to assign a value of type char (*)[5] to a value of type char *.
Compiler should report error on
char a[5] = {'A' , 'B' , 'C' , 'D'};
char *b = &a + 2; // <<< compile error
int i = 0 ;
for(i = 0 ; i < 4 ; i ++)
{
*b = (a[i] + 1);
printf("%c",*b);
}
and if you remove the line that generates compile error, the output should be no difference from your first piece of code.

Pointer arithmetic and address

I have come across a code which goes like :
#include <stdio.h>
int main(void)
{
int a[5] = { 1, 2, 3, 4, 5};
int *ptr = (int*)(&a + 1);
int *ptr2 = (int*) &a;
ptr2 +=1 ;
printf("%d %d %d \n", *(a + 1),*(ptr - 1) ,*ptr2 );
return 0;
}
The pointer arithmetic does it for me except this line :
int *ptr = (int*)(&a + 1);
Is it undefined behaviour ?
Why do we get 5 on dereferencing *(ptr - 1) ?
The size of a is "5 ints". So &a + 1 refers to the first memory location past all of a, since the pointer arithmetic is done in units of the size of a.
Try it out!
int a[5] = {1, 2, 3, 4, 5};
printf("%#x, %#x, %#x, %#x\n", a, &a, a+1, &a+1);
0xbfa4038c, 0xbfa4038c, 0xbfa40390, 0xbfa403a0
So what does that tell us?
0xbfa4038c == 0xbfa4038c which means a == &a. This is the address of the first element in the array or a[0].
We know that the size of an int is 4, and you know that *(a+1) == a[1] (the second element in the array) and this is proven by:
0xbfa4038c + 0x4 = 0xbfa40390 which means a + one int = address of the next element
Thus if we see &a+1 == 0xbfa403a0, that means we're ((0xa0-0x8c)/4) = 5 elements into the array. You know that a[5] is invalid, so that means we're one passed the end of the array.
so if you take:
int *ptr = (int*)(&a + 1); //one passed last element in the array
printf("%d",*(ptr - 1));//back up one, or last element in the array and deference
That's why you get 5
For an array of n elements of type T, then the address of the first element has type ‘pointer to T’; the address of the whole array has type ‘pointer to array of n elements of type T’;
int *ptr = (int*)(&a + 1); //&a-> address whole array, size=20 bytes,
//ptr=&a+1: next element =adress of a +20 bytes.
//ptr - 1 = address of a +16 = address of last a's element = address of 5

Incrementing variables using pointers

I'm very new to dealing with pointers, and my C knowledge is fairly small. I'm trying to understand pointers. I wrote the following code to print a list of variables (a to f) like so:
0
1
2
3
4
5
I wrote the following code to do this:
#include <stdio.h>
int main(){
int a,b,c,d,e,f;
int *p;
int i;
a = b = c = d = f = 0;
p = &a;
for (i = 0; i < 5; i++){
*p += i;
printf("%d\n", *p);
p++;
}
return 0;
}
The idea was it works through the variables and increments each by an ever-increasing number (i). I am assuming that as you initialize the variables at the same time, they'd be placed next to each other in memory. However, I get the following output:
0
1
2
3
-1218283607
If I change the for loop to only go from 0 to 3 (i < 4), it works fine, printer 0 1 2 and 3. But when I wish to print the variable f as well, it doesn't seem to set it.
As I said, I'm very new to pointers so I've probably overlooked something silly, but I've been looking through my code over and over, trying to work it out.
Thanks in advance.
There is no guarantee that a, b, c, d, e and f will be adjacent in memory. If you want that sort of guarantee you need to use an array.
#include <stdio.h>
int main() {
int a[6];
int *p;
int i;
a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = 0;
p = &a[0];
for (i = 0; i < 6; i++){
*p += i;
p++;
}
for(i = 0; i < 6; i++) {
printf("%d\n", a[i]);
}
return 0;
}
Here int a[6] is declaring an array named a that can hold six integers. These six integers can obtained via a[0], a[1], a[2], a[3], a[4] and a[5]. You are guaranteed that a[0], a[1], a[2], a[3], a[4] and a[5] are layed out contiguously in memory. Thus the line
p = &a[0];
sets p to the address of the first element. Each increment of this pointer moves us forward one position in the array.
The second for loop shows that first for loops correctly sets a[i] to i for i in {0, 1, 2, 3, 4, 5}. If you run this program you will see
0
1
2
3
4
5
on the console.
You forgot to initialize e. But yes, use a packed array.
It isn't safe to assume that stack variables are arranged in memory in any particular order.
You need to use an array, a struct or possibly a union to gurantee the ordering of your ints.
union {
int ary[6];
struct {
int a;
int b;
int c;
int d;
int e;
int f;
} s;
} u = {0};
p = &u.s.a;
for (i = 0; i < 5; i++){
*p += i;
printf("%d\n", *p);
p++;
}

Resources