#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]
Related
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.
#include <stdio.h>
void func(int **);
int main(void)
{
int ptr[2][3] = { {8, 7, 3}, {4, 5, 6} };
printf("ptr point is %p\n", ptr);
printf("*ptr point is %p\n", *ptr);
func(ptr);
system("pause");
return 0;
}
void func(int *ptr[8])
{
printf("ptr point is %p\n", ptr);
printf("*ptr point is %p\n", *ptr);
printf("*(ptr + 1) point is %p\n", *(ptr + 1));
}
Output:
ptr point is 004FFC24
*ptr point is 004FFC24
ptr point is 004FFC24
*ptr point is 00000008
*(ptr + 1) point is 00000007
Press any key to continue
Why ptr now becomes a 1D pointer?
As you can see
*(ptr) in func() output a 8;
*(ptr + 1) in func() output a 7;they are all digits in the array,
However, ptr should be 2D pointer, (because [] match with *, consequently *ptr[8] should match with **ptr).
so *(ptr + 1) and *(ptr) should be 1D pointers, instead of digits?
You have several issues.
First, you declare func to take a char **, but later define it to take int *[8], which doesn’t match. Even worse, both are wrong - or rather, they don’t match the type of the argument you’re passing.
Except when it is the operand of the sizeof or unary & operators, an expression of type “N-element of T” will be converted (“decay”) to an expression of type “pointer to T”, and the value of the expression will be the address of the first element.
When you pass ptr to func, it is converted from type “2-element array of 3-element array of int” to “pointer to 3-element array of int”, or int (*)[3]. So the function prototype needs to be
void func( int (*ptr)[3] )
or
void func( int ptr[][3] )
Because your function definition and declarations don’t match, and because neither matches the actual type of the argument, you get the unexpected output. You should have gotten a warning on the mismatched function argument types; if not, you may need to raise the warning level.
I know there are many similar questions, but I can't find an answer.
When passing the two-dimensional [3] [4] array to the function in my code below, how does the compiler know how far to increment the pointer, in the case of the last printf() where we are incrementing 3 x 4 memory locations, if the number 3 is missing in the function argument?
I mean, why is only arr [] [4] sufficient and not [3] [4]? Thanks
#include <stdio.h>
#include <stdlib.h>
int Fun(int arr[][4])
{
printf("%p\n", arr); // address of first element
printf("%p\n", arr[0] + 1); // address increments by 4, pointing to next "inner array"
printf("%p\n", arr + 1); // how does it know to increment address by 3 x 4 here? The complete array size
}
int main()
{
int arr[3][4] =
{
1,2,3,4,
5,6,7,8,
9,10,11,12
};
printf("%p\n", arr);
printf("%p\n", arr[0] + 1);
printf("%p\n", arr + 1);
printf("Passing to function\n");
Fun(arr);
return 0;
}
First, Fun should be defined with:
int Fun(int arr[][4])
rather than what you have, int Fun(int* arr[][4]);.
Next, when Fun(arr) is evaluated, arr is automatically converted from an array of 3 arrays of 4 int to a pointer to an array of 4 int. Similarly, in the declaration of Fun, int arr[][4] is automatically adjusted to be a pointer to an array of 4 int. So the argument type and the parameter type will match if you declare Fun correctly.
You could also declare Fun as:
int Fun(int (*arr)[4])
This is the same thing as above, due to the automatic adjustment that would be applied to the declaration above. Note that the asterisk here is grouped with the arr by the parentheses. This makes it a pointer to an array of int, rather than an array of pointers to int.
Now, as to what will be printed, in main:
printf("%p\n", arr);
In this statement, arr will be automatically converted to a pointer to its first element, so it becomes a pointer to an array of 4 int. Then the value of this pointer is printed. Note: When printing pointers, technically you should convert them to const void * or void *, as with printf("%p\n", (const void *) arr);. However, omitting this likely does not cause a problem at the moment.
printf("%p\n", arr[0] + 1);
In this statement, arr[0] is the first element of arr. That first element is an array of 4 int, and it is automatically converted to be a pointer to its first element. So arr[0] becomes a pointer to the first int. Then adding 1 advances the pointer to the next int. The result is likely an address four bytes beyond arr, depending on your C implementation. (It could be a different number of bytes, but four is the most common today.)
printf("%p\n", arr + 1);
In this statement, arr is converted to a pointer to its first element, an array of 4 int. Adding 1 advances to pointer to the next element, which is the next array of 4 int. So this likely adds 16 bytes to the address.
Then, in Fun:
printf("%p\n", arr); // address of first element
Here arr is a pointer to an array of 4 int. Its value is printed, yielding the same address as for the corresponding printf in main.
printf("%p\n", arr[0] + 1); // address increments by 4, pointing to next "inner array"
Here arr[0] is the object pointed to by arr, which is an array of 4 int. Since it is an array, it is automatically converted to a pointer to its first element, which is an int. So this points to the first int. Then adding 1 advances to the next int, and this again yields the same address as the corresponding printf in main.
printf("%p\n", arr + 1); // how does it know to increment address by 3 x 4 here? The complete array size
In this case, arr is a pointer to an array of 4 int, and adding 1 advances it to the next array of 4 int, so the result is likely 16 bytes beyond the value of arr, and this again yields the same address as the corresponding printf in main.
If you saw different values for the printf statements in Fun and main, this was likely because of the incorrect declaration with int* and because int * is eight bytes in your C implementation, compared to four for int. That error would have doubled some of the increments. You should not have seen any multiple of three in the increments.
Regarding the first dimension, Fun does not need to know the first dimension because it never advances any pointers by units of the first dimension. It receives only a pointer to an array of 4 int, and it does not need to know that there are 3 such arrays there.
The detailed answer by Eric Postpischil clearly shows all the issues in OP's code.
I'd like to note that passing a pointer to the correct type would let the compiler doing the right pointer arithmetic:
#include <stdio.h>
#include <stdlib.h>
void Fun(int (*arr)[3][4])
{
printf("Address of the first element: %p\n", (void *)*arr);
printf("Address of the second row: %p\n", (void *)(*arr + 1));
printf("Address after the last element: %p\n", (void *)(arr + 1));
}
void Fun_vla(size_t rows, size_t cols, int (*arr)[rows][cols])
{
printf("Address of the first element: %p\n", (void *)*arr);
printf("Address of the second row: %p\n", (void *)(*arr + 1));
printf("Address after the last element: %p\n", (void *)(arr + 1));
}
int main()
{
int arr[3][4] =
{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
Fun(&arr);
puts("");
Fun_vla(3, 4, &arr);
return 0;
}
I was reading through some lecture notes that in order for a pointer to reference a 2D array, it has to be given the address of the first element.
int a[10][10];
int *p = &a[0][0];
I've never tried this, so I was curious why isn't it enough to assign the array itself to the pointer, just as we do in a 1D case.
int a[10][10];
int *p = a;
The array is kept in an uninterrupted 'line' of memory anyway, and 2D arrays only have a different type, but the same structure as 1D arrays.
By doing this
int *p = &a[0][0];
I don't see how we give the pointer any more information than by doing this
int *p = a;
Or maybe all arrays regardless of their number of dimensions have the same type, the only difference being that multidimensional arrays store their extra dimensions before their first element and we need to jump over those memory spaces which remember sizes of an array's dimensions?
First, some background:
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("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.
Given the declaration
int a[10][10];
the expression a has type "10-element array of 10-element array of int". Unless this expression is the operand of the sizeof or unary & operators, it will be converted to an expression of type "pointer to 10-element array of int", or int (*)[10].
Given that declaration, all of the following are true:
Expression Type Decays to
---------- ---- ---------
a int [10][10] int (*)[10]
&a int (*)[10][10]
*a int [10] int *
a[i] int [10] int *
&a[i] int (*)[10]
*a[i] int
a[i][j] int
&a[i][j] int *
Also,
sizeof a == sizeof (int) * 10 * 10
sizeof &a == sizeof (int (*)[10][10])
sizeof *a == sizeof (int) * 10
sizeof a[i] == sizeof (int) * 10
sizeof &a[i] == sizeof (int (*)[10] )
sizeof *a[i] == sizeif (int)
sizeof a[i][j] == sizeof (int)
sizeof &a[i][j] == sizeof (int *)
Note that the different pointer types int (*)[10][10], int (*)[10], and int * don't have to be the same size or have the same representation, although on the platforms I'm familiar with they do.
The address of the first element of the array is the same as the address of the array itself; thus, all of a, &a, a[0], &a[0], and &a[0][0] will yield the same value, but the types will be different (as shown in the table above).
So, assume we add the following declarations:
int *p0 = &a[0][0]; // equivalent to int *p0 = a[0];
int (*p1)[10] = &a[0]; // equivalent to int (*p1)[10] = a;
int (*p2)[10][10] = &a;
All of p0, p1, and p2 initially have the same value, which is the address of the first element in a; however, because of the different pointer types, the results operations involving pointer arithmetic will be different. The expression p0 + 1 will yield the address of the next int object (&a[0][1]). The expression p1 + 1 will yield the address of the next 10-element array of int (&a[1][0]). And finally, the expression p2 + 1 will yield the address of the next 10-element array of 10-element array of int (effectively, &a[11][0]).
Note the types of p1 and p2; neither is a simple int *, because the expressions being used to initialize them are not that type (refer to the first table).
Note the pattern; for an array type, the simpler the expression, the more complicated the corresponding type will be. The expression a does not refer to a single int object; it refers to a 10x10 array of int objects, so when it appears in an expression, it is treated as a pointer to an array of integers, not a pointer to a single integer.
The compiler knows that "a" is a pointer to ten integers. If you don't declare the dimensions, then the compiler sees the new pointer as a pointer to an unknown number of integers. This will work in your case, but it will generate a compiler warning because the compiler sees them as incompatible pointers. The syntax for what you are trying to do (without generating a compiler warning) is:
int a[10][10];
int *p1 = &a[0][0];
int (*p2)[10] = a;
printf("p1: %p p2: %p\n", p1, p2);
One reason this is important is pointer arithmetic:
p1++; //move forward sizeof(int) bytes
p2++; //move forward sizeof(int) * 10 bytes
You understanding is close, the difference is the type information. Pointer does has its type. For example int* p, the pointer type is int*, as int a[10][10], the corresponding pointer type is int *[10][10].
In your example, p and a do point to the same address, but they're different type, which matters when perform arithmetic operation on them.
Here's an example from this URL
Suppose now that we define three pointers :
char *mychar;
short *myshort;
long *mylong;
and that we know that they point to the memory locations 1000, 2000, and 3000, respectively.
Therefore, if we write:
++mychar;
++myshort;
++mylong;
mychar, as one would expect, would contain the value 1001. But not so obviously, myshort would contain the value 2002, and mylong would contain 3004, even though they have each been incremented only once. The reason is that, when adding one to a pointer, the pointer is made to point to the following element of the same type, and, therefore, the size in bytes of the type it points to is added to the pointer.
You are right, you can assign the array itself to the pointer:
int a[10][10] = {[0][0]=6,[0][1]=1,[1][0]=10,[1][1]=11};
int b[10][10][10] = {[0][0][0]=8,[0][0][1]=1,[0][1][0]=10,[1][0][0]=100};
int *p, *q, *r, *s;
p = &a[0][0];
q = a; // what you are saying
r = &b[0][0][0];
s = b; // what you are saying
printf("p= %p,*p= %d\n",p,*p);
printf("q= %p,*q= %d\n",q,*q);
printf("r= %p,*r= %d\n",r,*r);
printf("s= %p,*s= %d\n",s,*s);
And the output is:
p= 0xbfdd2eb0,*p= 6
q= 0xbfdd2eb0,*q= 6
r= 0xbfdd3040,*r= 8
s= 0xbfdd3040,*s= 8
They point to the same address, regardless of the dimension of the matrix. So, what you are saying is right.
Well in 2D array, the outcome of *a and a is the same, they all point to the first address of this 2D array!
But if you want to define a pointer to point to this array, you could use int (*ptr)[10] for example.
You are right, 1D and 2D share the same structure, but 2D has some additional manipulation on pointers like above.
So all in all, in 2D array, a, *a and &a[0][0] prints the same address, but their usages may vary.
Like this:
#include<stdio.h>
int main() {
int a[10][10];
int *pa1 = &a[0][0];
int *pa2 = *a;
printf("pa1 is %p\n", pa1);
printf("pa2 is %p\n", pa2);
printf("Address of a is %p\n", a);
// pointer to array
int (*pa3)[10];
pa3 = a;
printf("pa3 is %p\n", pa3);
return 0;
}
They print the same 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).