A pointer to an address of an array - arrays

Why does this code output: 1 ≡ arr[0] and not &arr[0]?
My assumption is that after the assignment, ptr holds the address of &arr, which is a pointer to the first element of arr or arr[0].
So dereferencing the ptr should yield the value stored at that address, which is the memory location of the first element.
#include<stdio.h>
int main(void) {
int arr[] = { 1 };
int* ptr = &arr;
printf("%d\n", *ptr);
return 0;
}

A couple of things...
First, a doesn't store the location of a[0]. There is no object a that is separate from the array element a[0]. Basically what you have in memory is
Address
------- +------+
0x1000 a: | 0x01 | a[0]
+------+
In other words, the address of an array is the same as the address of its first element.
Unless it is the operand of the sizeof or unary & operators, the expression a will be converted ("decay") from type "1-element array of int" (int [1]) to "pointer to int" (int *) and the value of the expression will be the address of the first element in the array.
This means that the expressions &a, a, and &a[0] all yield the same address value; it's just the types of the expressions are different:
Expression Type Decays to
---------- ---- ---------
&a int (*)[1]
a int [1] int *
&a[0] int *
Which brings us to this line:
int* ptr = &arr; // int * = int (*)[1] - assignment of incompatible types
The compiler should have yelled at you about that line. You may want to dial up the warning level.

I added some print statements to your code:
#include<stdio.h>
int main(void) {
int arr[] = { 1 };
int *ptr = (int *)arr;
printf("%p\n", (void *)arr);
printf("%p\n", (void *)&arr);
printf("%p\n", (void *)&arr[0]);
printf("%p\n", (void *)ptr);
printf("%p\n", (void *)&ptr);
printf("%d\n", *ptr);
return 0;
}
It prints:
0x7ffe3fe37aa4
0x7ffe3fe37aa4
0x7ffe3fe37aa4
0x7ffe3fe37aa4
0x7ffe3fe37a98
1
Which means arr and ptr are on the stack: ptr is at 0x7ffe3fe37a98 and has the value 0x7ffe3fe37aa4, which is where the arr is stored.
Note that arr and &arr have the same value. See this question: How come an array's address is equal to its value in C?
My assumption is that after the assignment, ptr holds the address of &arr, which is a pointer to the first element of arr or arr[0].
That is correct.
So dereferencing the ptr should yield the value stored at that address
Also correct.
which is the memory location of the first element.
No. Since ptr is pointing to the first element, dereferencing yields the first element, which is 1.

Related

When I point a pointer to an array. Why does the pointer and the index[0] of the array I am pointing to have different memory addresses?

#include <stdio.h>
int main()
{
int arr[5];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
arr[3] = 40;
arr[4] = 50;
int *p = &arr;
printf("Memory address of first index: %p\n", &arr[0]);
printf("Memory address of pointer: %p\n", &p);
return 0;
}
OUTPUT
Memory address of first index: 000000000061FE00
Memory address of pointer: 000000000061FDF8
They are are not the same. Is my machine bad?
First of all the compiler should issue a message relative to this declaration
int *p = &arr;
The problem is that the right hand side expression has the type int( * )[5] while the initialized object has the type int * and there is no implicit conversion between these two pointer types.
You should write either
int *p = arr;
In this case the array designator is implicitly converted to a pointer to its first element. Or
int ( *p )[5] = &arr;
The pointer p occupies its own extent of memory. So its address is different from the address of the extent of the memory occupied by the array arr.
On the other hand, if you will output the value stored in the pointer p like for example
printf("Memory address stored in the pointer p: %p\n", ( void * )p);
then it will be equal to the address of the first element of the array arr
printf("Memory address of first index: %p\n", ( void )&arr[0]);
arr is an array. It and its elements start at some place in memory.
p is a pointer to the array. Its value is an address. That address needs to be stored somewhere else in memory. That place is different from where the array is stored.
printf("%p\n", (void *) p); prints the value of p, which will be the address of arr (and of &arr[0], since the first element is at the start of the array).
printf("%p\n", (void *) &p) prints the address of p, which is where p is.

Array and pointer (something like &arr)

#include <stdio.h>
int main()
{
int *a, *b,*c,**d;
int arr[10]={0};
a=arr;
b=&arr;//is this true?why?
c=&arr[0];
d=&a;
printf("%p,%p,%p,%p",a,b,c,d);
return 0;
}
Does &arr something point to the first address of the array?
Is b=&arr; true?
What's the difference between arr and &arr?
Does &arr something point to the first address of the array?
&arr is pointer to whole array of 10 integers and not the pointer to first element of the array.
Is b=&arr; true?
No, given int *b, then b=&arr; is an incompatible pointer type assignment because the type of &arr is int (*)[10] whereas the type of b is int *. (If the definition is int (*b)[10], there is no problem.)
what is the difference between arr and &arr?
The arr, when used in a statement, will be converted to pointer to first element of array (there are few exceptions to this rule). The type of arr is int * and it is equivalent to &arr[0]1) (i.e. both are pointer to first element of array).
The &arr is pointer to the whole array (it's type is int (*)[10]).
The address of an array (&arr) and address of first element of an array (arr or &arr[0]) is numerically same though their type is different. That means, if we add 1 to them there results will be different (provided that the array size is greater than 1). arr + 1 result in pointer to 2nd element whereas &arr + 1 result in pointer after 10 elements of array arr.
Demonstration:
#include<stdio.h>
int main (void) {
int arr[10];
printf ("arr - %p\n", (void *)arr);
printf ("&arr - %p\n", (void *)&arr);
printf ("arr + 1 - %p\n", (void *)(arr + 1));
printf ("&arr + 1 - %p\n", (void *)(&arr + 1));
return 0;
}
Output:
# ./a.out
arr - 0x7ff7bec77950
&arr - 0x7ff7bec77950
arr + 1 - 0x7ff7bec77954
&arr + 1 - 0x7ff7bec77978
Also, when using the format specifier %p in printf(), the corresponding argument('s) should be type casted to (void *).
1). From C11 Standards#6.5.2.1
The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))..
Hence,
arr -> (arr + 0) -> &( *(arr + 0) ) -> &arr[0]

Casting pointer syntax (to an array address like a smaller sized array) in C language

I have an array with 10 int elements, and I want to point a pointer to this array, not with full size but half. By this, I can reach the first 5 elements by using ptr and the second 5 elements by increasing pointer one ptr++.
I just want to know how can I CAST, I don't need to know workarounds or union or struct or anything else...
I just wonder the syntax of such a thing.
Here is the example that I struggle with ;
// Pointer to an integer
int *p;
// Pointer to an array of 5 integers
int (*ptr)[5]; // this could be void*
int arr[10];
// Points to 0th element of the arr.
p = arr;
// Points to the whole array arr.
ptr = (int[5]*)&arr; // when arr sized as 5 , ptr = &arr; gives result a pointer "ptr" with size of 5
printf("p = %p, ptr = %p\n", p, ptr);
p++;
ptr++;
printf("p = %p, ptr = %p\n", p, ptr);
return 0;
Note:
The answer is: ptr = (int(*)[5])&arr; (compiler's warning message helped me out to find this answer, it was not able to convert one to another type ... )
But I really don't know what is the () and why it is not the same thing as int*[5]. I really don't understand the purpose of parenthesis there.
If I understand what you’re asking for, this is what you want:
ptr = (int (*)[5]) &arr;
The expression &arr has type int (*)[10] (pointer to 10-element array of int). Since ptr has type int (*)[5] (pointer to 5-element array of int), we just need to cast the result of &arr to that type.
Remember the following precedence rules:
T *a[N]; // a is an array of pointer to T
T (*a)[N]; // a is a pointer to an array of T
T *f(); // f is a function returning pointer to T
T (*f)(); // f is a pointer to a function returning T
Unary * has a lower precedence than [] and (), so an expression like *a[i] is parsed as *(a[i]) - you’re dereferencing the result of a[i]. If a is a pointer to an array, then you need explicitly group * with a so you index into what a points to - (*a)[i].
Define a typedef to make the casting easier.
typedef int (*int5ptr)[5];
// Pointer to an integer
int *p;
// Pointer to an array of 5 integers
int5ptr ptr;
int arr[10];
// Points to 0th element of the arr.
p = arr;
// Points to the whole array arr.
ptr = (int5ptr)&arr;
printf("p = %p, ptr = %p\n", p, ptr);
p++;
ptr++;
printf("p = %p, ptr = %p\n", p, ptr);

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)

Single dimensional array address

char arr[10]="hello";
I guess &arr in this array is of type char(*)[10].
If I am right, what is the type of *(&arr)? Is it of type base address or address to first element in array?
Given:
char arr[10];
as you say, &arr is of type char (*)[10]. Of itself, *(&arr) is of type char [10], but in most contexts (other than sizeof()) it will become char * when it is used.
Sample code:
#include <stdio.h>
int main(void)
{
char arr[10] = "hello";
printf("arr[10] = \"%s\"\n", arr);
printf("arr = %p\n", arr);
printf("&arr = %p\n", &arr);
printf("*(&arr) = %p\n", *(&arr));
printf("sizeof(*(&arr)) = %zu\n", sizeof(*(&arr)));
printf("arr+1 = %p\n", arr+1);
printf("&arr+1 = %p\n", &arr+1);
printf("*(&arr) = \"%s\"\n", *(&arr));
return 0;
}
Sample output (GCC 4.7.1, Mac OS X 10.8.3):
arr[10] = "hello"
arr = 0x7fff4ff15500
&arr = 0x7fff4ff15500
*(&arr) = 0x7fff4ff15500
sizeof(*(&arr)) = 10
arr+1 = 0x7fff4ff15501
&arr+1 = 0x7fff4ff1550a
*(&arr) = "hello"
Note that although the values of arr and &arr are the same, the types are different. This is most clearly demonstrated by the arr+1 and &arr+1 lines. As you can see, incrementing &arr by one adds the sizeof of the object it points at (a char [10]) to the address.
You can extend the example to add other values as you see fit.
The expression *(&arr) is the same type as arr. The dereference and address-of operators cancel out each other out.
You use the address-of operator & to get the address, i.e. get a pointer. You use the dereference operator * to get the value of what a pointer points to. So using both of them like that doesn't make any sense in that context.
*(&arr) is of type base address, where as *(&arr[0]) is the first element in the array.
char arr[10];
arr has type "array of 10 chars" and &arr is "pointer to array of 10 chars." , *(&arr) is the same as arr, and has the same type, i.e, base address.
&arr[0] will yield a pointer that points to the first element address.
a, *(&a), &a[0] are same (base address of array a/ address of the first element of array a).

Resources