Pointers problems with C - c

I don't understand the difference in the t and p pointers. The t pointer gives the same output when printing t and *t only when using **t I get the value.
What's the difference between them?
The code is:
int main()
{
int B [2][3] = {
{2, 3, 6},
{4, 5, 8}
};
int *p = B;
int (*t)[3] = B;
printf ("%d\n", p);
printf ("%d\n", t);
printf ("%d\n", *p);
printf ("%d\n", *t);
printf ("%d\n", **t);
return 0;
}
Output is:
6422000
6422000
2
6422000
2

Comments have addressed the importance of using the correct format specifiers, but here are a couple of other points to consider:
point 1:
The declaration: int *p = B; should generate a compile time warning. This is because int *p is a simple pointer to int, as such it should only be set to point to the address of (&) a single int. But B does not represent an int.
For illustration, it is instructive to see the variations of warnings for the following 3 incorrect ways of initializing p with B. Each starts off with the phrase:
_"warning: incompatible pointer types initializing `int *` with an..."_:
int *p = B;//...expression of type 'int [2][3]'
int *p = &B;//...expression of type 'int (*)[2][3]'
int *p = &B[0]//...expression of type 'int (*)[3]'
Note the incompatible pointer types at the end of each warning. Each of them is specific, providing the programmer hints how to address the potential problem.
The following initializes *p with the address of a single int and generates no warning
int *p = &B[0][0];//assigning address of p to the location of a single integer value.
point 2:
The following declaration/assignment:
int (*t)[3] = B;
creates t as a pointer to an array of 3 int, and points t to the first instance (row) of 3 int in B where B is defined as:
int B [2][3] = {{2, 3, 6}, {4, 5, 8}};
Because t is defined in this way it is flexible in the way it can be used in that it is pointable to any array of 3 int i.e. it does not matter how many rows B has, or to which row t is pointed. Example, given the following arrays:
int B[5][3] = {{1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}, {13,14,15}};
int A[3] = {0}; //A simple array of 3 int all set to 0
The following declarations can be made:
int (*t)[3] = NULL; //points to nothing
t = B; //points to location of 1st element of 1st row in B
t = &B[1]; //points to location of 1st element of 2nd row in B
t = &B[4]; //points to location of 1st element of 5th row in B
t = &A; //points to location of 1st element of A

Writing int *p = B; isn't a good idea but anyway, it puts the address of the very first element of B, 2 into p. So, p outputs the address(6422000) and *p outputs 2. All good till here.
What is t? It's a pointer to an array, B. What will happen when you print it, you'll get the address to B, which is always also the address of it's very first element, which happens to be 6422000. So, what will happen when you dereference t? You'll get and array, B in this case, which will then decay into a pointer and give you the memory address. And the memory address of B is 6422000. And **t will dereference the dereferenced array. The deference array is B, which will decay into the pointer, 6422000 in this case and that will be dereferenced again, giving 2.
Basically:
p: Address of the very first element of B, 2.
*p: Dereferenced p, in this case 2.
t: Address to B. Address of an array is also the address of it's very first element, equivalent to p.
*t: Dereferences into B, B will decay into it's very first element's pointer, equivalent to p.
**t: Dereferenced *t, which is 2.
Note: I know, the first element of B is {2, 3, 6}, not 2. I refer to 2 as "the very first element". That's inaccurate but for the purpose of explanation, I was forced to use the terminology.

Related

Pointer variable pointing to a one dimensional array or two dimensional array?

I have the following code for a one dimensional array:
#include <stdio.h>
int main()
{
static int b[4] = {11, 12, 13, 14};
int (*p)[4];
p = b;
printf("%d \n", *(p + 1));
return 0;
}
Even though I consider "b (the array name)" as a pointer pointing to a one dimensional array, I got a compiling error as
'=': cannot convert from 'int [4]' to 'int (*)[4]'
However, if I change b array into a two dimensional array "a (the array name)", everything works fine. Does this mean that, in the usage of "int (*p)[4];", "*p" has to represent a[] as in the following:
static int a[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
int (*p)[4];
p = a;
As a result, "int (*p)[4]" only provides the flexibility on the number of rows of a two dimensional array.
Any insights on this problem?
Arrays naturally decay to pointers to their first elements, depending on context. That is, when such a decay happen then plain b is the same as &b[0], which have the type int *. Since the types of p and b (or &b[0]) are different you get an error.
As for a it's the same thing here, it decays to a pointer to its first element, i.e. a is the same as &a[0]. But since a[0] is an array of 4 elements, then &a[0] is a pointer to an array of four elements, or int (*)[4]. Which is also the type of p in the second example.
If you have an object of some type T like
T a;
then declaration of a pointer to the object will look like
T *p = &a;
Your array b has the type int[4]. So a pointer to the array will look like
int ( *p )[4] = &b;
To output the second element of the array using the pointer you should write
printf("%d \n", *( *p + 1 ) );
Thus your compiler issued the error message
cannot convert from 'int [4]' to 'int (*)[4]
because instead of writing at least
int ( *p )[4] = &b;
you wrote
int ( *p )[4] = b;
On the other hand, an array designator used in expressions with rare exceptions is implicitly converted to pointer to its first element. For example in this declaration
int *p = b;
the array b used as an initializer is converted to pointer to its firs element. The above declaration is equivalent to
int *p = &b[0];
or that is the same
int *p = b + 0;
Using this pointer you can call the function printf like
printf("%d \n", *(p + 1));
If you have a two-dimensional array as
int a[3][4];
then used in expressions it is converted to pointer to its first element that has the type int[4]. So you may write
int ( *p )[4] = a;
If you want to declare a pointer to the whole array as a single object you can write
int ( *p )[3][4] = &a;
a pointer pointing to a one dimensional array,
No, it points directly to the first element. Likewise:
int *p = b;
is enough.
The number 4 is not really part of any type here;
static int b[] = {11, 12, 13, 14};
It can be left out in the declaration. (Because it is the first dimension unless you make it 2D)
This (from AA)
int (*p)[4] = &b;
...
printf("%d \n", *( *p + 1 ) );
is just a obfuscated and overtyped version of:
int (*p)[] = &b;
...
printf("%d \n", (*p)[1] );
This replaces b with (*p), normally not what you want.

Pointer to an entire array

I stumbled upon "pointer to the entire array" and wrote a test program to clear some things out:
#include <stdio.h>
int main(){
int x[5] = {1, 2, 3, 4, 5};
int *a = x; // points to the 1st array element
int (*b)[5] = &x; // points to the 1st addres of the stream of 5 int elements
int (*c)[5] = x; // points to the 1st addres of the stream of 5 int elements
printf("%p\n%p\n%p\n\n",
(void *)a,
(void *)b,
(void *)c
);
++a;
++b;
++c;
printf("%p\n%p\n%p\n\n",
(void *)a,
(void *)b,
(void *)c
);
return 0;
}
This outputs:
0x7ffed0c20690
0x7ffed0c20690
0x7ffed0c20690
0x7ffed0c20694
0x7ffed0c206a4
0x7ffed0c206a4
To me it looks like lines:
int (*b)[5] = &x;
int (*c)[5] = x;
achieve exact same result, because:
they assign the same addres (in case of *b it is the address of entire array and in case of *c it is the address of the first array member but those two overlap) and
assign same pointer size of 5 · int for *b and *c which leads to the exactly same pointer arithmetics when I increment the values.
Q1: Are there any hidden differences between definitions of *b and *c that I am missing?
Q2: Does pointer arithmetics only depends on the size of the pointer?
After you pointed I noticed that I do get an error:
main.c:9:16: warning: initialization of ‘int (*)[5]’ from incompatible pointer type ‘int *’ [-Wincompatible-pointer-types]
int (*c)[5] = x; // points to the 1st array element
Q1: Are there any hidden differences between definitions of *b and *c that I am
missing?
Pointer arithmetic on these two pointers will remain the same. Because internally array decays into the pointer to the first element in it, i.e. arr[n] will be converted to an expression of type "pointer to arr", and its value will be the address of the first element in the array.
Q2: Does pointer arithmetics only depends on the size of the pointer?
No, it depends on the size of the underlying type pointed to. Even in your provided sample input ++a and ++b are yielding different results. Because ++a offsets pointer by sizeof(int) which is 4. But in case of ++b your pointer is incremented by size of 5 * sizeof(int) by 20 (decimal)

How are array of pointers stored in memory and how to properly dereference them?

int main(void) {
int* b[3] = {1, 2, 3}; // b is an array of pointers to integer
printf("%d", b); // b = address of array of pointers
printf("\n%d", *b); // *b should be address of the place where 1 is stored ....right?
printf("\n%d", *(b+1)); // similarly *(b+1) should be address of place where 2 is stored
printf("\n%d", *(b+2)); // and so on... But they print 1,2 and 3
printf("\n%d", b[0]); // prints 1 . No problem!
printf("%d", *(*(b+1)+2)); // Also why does this give segmentation fault?
//PLUS I GET THIS WARNING : array_of_pointers2.c:5:13: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
//PLEASE EXPLAIN !! I think I have misunderstood something.
return 0;
}
Below I have attatched a sketch of how I think they are stored. Please correct me with a better sketch if I am wrong.
Your code has many problems, mostly coming from the fact that int *b[3] does not have a proper initializer. { 1, 2, 3 } is OK for an array of int, not for an array of int *, as the compiler correctly diagnoses:
array_of_pointers2.c:5:13: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
For compatibility with ancient code, the compiler only issues a warning, but such warnings indicate errors that must be corrected. I strongly suggest you compile your code with -Wall -Werror to let the compiler produce errors instead of mere warnings for such problems.
Accessing adresses 1, 2 or 3 most likely has undefined behavior, which takes the form of a segmentation fault on your system.
To initialize the array of pointers, you can specify the addresses of int variables.
Here is a corrected version:
#include <stdio.h>
int main(void) {
int x = 1, y = 2, z = 3;
int *b[3] = { &x, &y, &z }; // b is an array of pointers to integer
printf(" b: %p\n", (void*)(b)); // b = address of array of pointers
printf(" *b: %p\n", (void*)(*b)); // *b is the address of variable x that has a value of 1
printf(" *(b+1): %p\n", (void*)(*(b+1))); // similarly *(b+1) is the address of y where 2 is stored
printf(" *(b+2): %p\n", (void*)(*(b+2))); // and so on...
printf(" *b[0]: %d\n", *b[0]); // prints 1. No problem!
printf("*(*(b+1)): %d\n", *(*(b+1))); // prints 2
// accessing *(*(b+1)+2) would have undefined behavior because b[1] is
// not the address of an array of at least 3 ints.
printf(" b[2][0]: %d\n", b[2][0]); // prints 3
return 0;
}
Note that pointers cannot be printed with %d as it has undefined behavior because pointers may be passed differently from integers to printf. The format is %p and the pointer should be cast as (void*) for complete portability.
Arrays are stored consecutively in the address space.
Their allocation is static, meaning you don't allocate space for it at run time and as a result of this, they are stored in different memory region - stack.
An array determines its size by the amount of elements multiplied by the size of the data type, (because you have packed a variable n-times).
The size is the space in bytes it occupies in the memory. It should not be confused with the length of the array, which is how many elements are in the array. For example int arr[2] is usually 8 bytes (sizeof(int[2])) but is an array with the length of 2.
There are many ways to initialize array, but two ways to de-reference it.
One is by using the index operators [] and the other is to de-reference the pointer it decays to with * Example:
int arr[3];
arr[0] = 40;
*arr = 40;
arr[2] = 40; // <-- this is functionally equivalent to..
*(arr + 2) = 40; // <--this (Note the pointer arithmetic involved)
int* arr[3] - This is an array of int pointers.
The index operator has very high precedence, higher than *
To get around that, and substantially create a pointer to an array of 3 elements, you use the brackets to define the priority of evaluation:
int (*arr)[3];
Bracket's second use-case is to make a "derived type" - a function. ([], *, () are used to define a derived type)
How to initialize them at declaration time?
An array of characters
char arr[3] = {'a', 'b', 'c'}
char arr[] = {'a', 'b', 'c'}
char arr[3] = "hi" // Note this is a string, not array of characters anymore
To initialize the first element of an array of int pointers you can very well do this:
char ch1 = 'a';
char* arr[3] = { &ch1 };
And finally, initialize a pointer to an array of 3 characters:
char arr[3] = {'a', 'b', 'c'};
char (*arr2)[3] = arr;
int* b[3] = {1, 2, 3};
This is stored like this:
b
+-----+
| 1 |
+-----+
| 2 |
+-----+
| 3 |
+-----+
You asked for an array containing 1, 2, and 3, and you got an array containing 1, 2 and 3. It does not create separate variables containing 1, 2 and 3 and then put pointers to those variables in the array. No, it just puts 1, 2 and 3 in the array and carries on.
The warning is because it is very uncommon and usually wrong to be writing a memory address directly. What's at memory address 1? Damned if I know. Probably it's not even a valid address, so when you do *b[0] it just crashes.
*b is the same as b[0], *(b+1) is the same as b[1] and so on. So those are just fetching the "pointers" in the array - not the things they point to.
*(*(b+1)+2) segfaults because it's accessing address 10 (on a 32-bit system). Probably 10 isn't a valid address of anything either. So you get a segfault.

Arrays decaying into pointers

Please help me understand the programs below.
#include<stdio.h>
int main()
{
int a[7];
a[0] = 1976;
a[1] = 1984;
printf("memory location of a: %p", a);
printf("value at memory location %p is %d", a, *a);
printf("value at memory location %p is %d", &a[1], a[1]);
return 0;
}
&a[1] and &a+1. Are they same or different?
#include <stdio.h>
int main()
{
int v[10];
int **p;
int *a[5];
v[0] = 1234;
v[1] = 5678;
a[0] = v;
a[1] = v+1;
printf("%d\t%d\t%d\t%d\n", *a[0],*a[1],a[0][0],**a);
printf("%d\n", sizeof(v));
return 0;
}
I wanted to know how *a[5] is represented in memory. Is *a a base pointer that points to a[0],a[1],a[2],a[3],a[4]?
#include<stdio.h>
int main()
{
int v[10];
int **p;
int (*a)[10];
a=&v;
printf("%d\n",*a);
return 0;
}
a=v; // gives error why? does v here decay into *v. Then does &v get decayed into (*)[]v? & means const pointer. Here, how is it possible to set a const pointer to a non-const pointer without a typecast?
Where does the array get stored in the memory. Does it get stored onto the data segment of the memory.
#include<stdio.h>
int main()
{
int carray[5]={1,2,3,4,5};
printf("%d\n",carray[0]);
printf("%d\t%d\t%d\n",sizeof(carray),sizeof(&carray),sizeof(&carray[0]));
return 0;
}
EDITED:
I have gone through some of the articles which stated that the only two possible situations where an array name cannot be decyed into pointer is the sizeof and &. But in the above program sizeof(&carray) gives the size as 4. and &carray decays into (*)[]carray as its an rvalue.
Then the statement that array name cannot get decayed into pointers on two conditions sizeof and & becomes false here.
&a[1] and &a+1. Are they same or different?
Different. &a[1] is the same as (a+1). In general, x[y] is by definition equivalent to *(x+y).
I wanted to know how *a[5] is represented in memory. Does *a is a base
pointer that points to a[0],a[1],a[2],a[3],a[4].
In your second example, a is an array of pointers. *a[i] is the value of the object, the address of which is stored as the ith element in your array. *a in this case is the same as a[0], which is the first element in your array (which is a pointer).
a=v //why this gives error
Because a (in your last example) is a pointer to an array. You want to assign to a, then you need to assign the address of the array v (or any other array with correct dimensions);
a = &v;
This is very good that you've commited to understanding things, but nothing will help you better than a good C book.
Hope this helps.
Stuff you are gonna need to know when dealing with pointers is that:
int *a and int a[]
is a declaration of an Array, the only diffrence is that in a[] youre gonna have to declare its constant size, *a gives you flexability, it can point at an array size 1 to infinity
int *a[] and int **a
is a declaration of an Array of Array,sometimes called Matrix, the only diffrence is that in *a[] youre gonna have to declare how many Arrays a[] gonna contain pointers of, **a gives you flexability, it can point at any Array of arrays that you want it to be assigned to.
IN GENERAL:
When adding & to a variable, your adding a * to its Type definition:
int a;
&a -> &(int)=int*
when adding * to a variable, you decrase a * from its Type definition
int *a;
*a -> * (int * )=int
int *a;
&a - the Address given to the pointer a by the system(pointer of pointer = **a)
&a+1 - the Address to the beginning of the array + 1 byte
&a[1] == &(a+1) - the Address to the beginning of the array + 1 size of int
int **a;
*a == a[0] - the Address of the first Array in the array of arrays a
*a[0]==a[0][0] - the first int of first array
int *a, b[5];
*a=*b - ERROR because a points at garbage to begin with
a=b - a points at array b
ask me what else you want to know and ill edit this answer.

Difference between pointer to pointer and pointer to array?

Given that the name of an array is actually a pointer to the first element of an array, the following code:
#include <stdio.h>
int main(void)
{
int a[3] = {0, 1, 2};
int *p;
p = a;
printf("%d\n", p[1]);
return 0;
}
prints 1, as expected.
Now, given that I can create a pointer that points to a pointer, I wrote the following:
#include <stdio.h>
int main(void)
{
int *p0;
int **p1;
int (*p2)[3];
int a[3] = {0, 1, 2};
p0 = a;
p1 = &a;
p2 = &a;
printf("p0[1] = %d\n(*p1)[1] = %d\n(*p2)[1] = %d\n",
p0[1], (*p1)[1], (*p2)[1]);
return 0;
}
I expected it to compile and print
p0[1] = 1
(*p1)[1] = 1
(*p2)[1] = 1
But instead, it goes wrong at compile time, saying:
test.c: In function ‘main’:
test.c:11:5: warning: assignment from incompatible pointer type [enabled by default]
Why is that assignment wrong? If p1 is a pointer to a pointer to an int and a is a pointer to an int (because it's the name of an array of ints), why can't I assign &a to p1?
Line 11 is
p1 = &a;
where p1 has type int ** and a has type int[3], right?
Well; &a has type int(*)[3] and that type is not compatible with int** as the compiler told you
You may want to try
p1 = &p0;
And read the c-faq, particularly section 6.
In short: arrays are not pointers, and pointers are not arrays.
a is not a pointer to int, it decays to such in certain situations. If &a was of type int ** you couldn't very well use it to initialize p2, could you?
You need to do p1 = &p0; for the effect you want. "pointer to pointer" means "at this address, you will find a pointer". But if you look at the address &a, you find an array (obviously), so int ** is not the correct type.
For many operations, a implies &a and both return the same thing: The address of the first item in the array.
You cannot get the address of the pointer because the variable does not store the pointer. a is not a pointer, even though it behaves like one in some cases.

Resources