[英]Why won't *num show the zeroth element value?
In this code: 在此代码中:
#include<stdio.h>
int main()
{
int num[2] = {20, 30};
printf("%d", num);
printf("%d", &num[0]);
return 0;
}
As far as I know, both the printf statement will print the address of the first element in num
because in the first statement, num
is a pointer to an int. 据我所知,两个printf语句都将打印
num
中第一个元素的地址,因为在第一个语句中, num
是一个指向int的指针。
But if num
is a pointer, then it should also have any address but on printing its address (with printf("%d", &num)
), it's showing the address of the first element. 但是,如果
num
是一个指针,那么它在打印地址时也应该有任何地址(使用printf("%d", &num)
),它显示的是第一个元素的地址。
In a 2-D array the whole thing becomes confusing too: 在二维数组中,整个事情也变得令人困惑:
#include<stdio.h>
int main(void)
{
int num[ ] [2]={20,30,40,50};
printf("%d",*num);
return 0;
}
This program is printing the address of zeroth element that is the address of num[0][0]
. 该程序将打印第零个元素的地址,即
num[0][0]
的地址。 But why does it do this? 但是为什么要这样做呢? Why isn't it printing the value stored in it, since they all have same address(
num,num[0]
and num[0][0]
)? 为什么它们不打印存储在其中的值,因为它们都具有相同的地址(
num,num[0]
和num[0][0]
)?
First things first; 首先是第一件事; array variables are not pointers;
数组变量不是指针; they do not store an address to anything.
他们不存储任何地址。
For a declaration such as 对于诸如
T a[N];
memory will be laid out as 内存将被布置为
+---+
a[0]: | |
+---+
a[1]: | |
+---+
...
+---+
a[N-1]: | |
+---+
For a 2D MxN array, it will look like 对于2D MxN阵列,它看起来像
+---+
a[0][0]: | |
+---+
a[0][1]: | |
+---+
...
+---+
a[0][N-1]: | |
+---+
a[1][0]: | |
+---+
a[1][1]: | |
+---+
...
+---+
a[M-1][N-1]: | |
+---+
The pattern should be obvious for 3D and higher arrays. 对于3D和更高级别的阵列,该模式应该很明显。
As you can see, no storage is set aside for a separate variable a
that contains the address of the first element; 如您所见,没有为包含第一个元素的地址的单独变量
a
保留存储空间。 instead, there is a rule in the C language that 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, except when the array expression is one of the following: 相反,有在C语言类型“的N元件阵列的表达的规则
T
”将被转换 (“衰变”),以式“指针的表达T
”和表达式的值将是数组第一个元素的地址, 但数组表达式为以下之一时除外 :
sizeof
operator sizeof
运算符的操作数 &
operator &
运算子的运算元 _Alignof
operator (C99 and later) _Alignof
运算符的操作数(C99和更高版本) So given the declaration 所以给了宣言
T a[N];
all of the following are true: 满足以下所有条件:
Expression Type Decays to Value
---------- ---- --------- -----
a T [N] T * address of first element, &a[0]
*a T n/a value stored in first element
&a T (*)[N] n/a address of the array, which is
the same as the address of the
first element of the array
a[i] T n/a value stored in the i'th element
&a[i] T * n/a address of the i'th element
sizeof a size_t n/a total number of bytes used by the
array
sizeof *a size_t n/a total number of bytes used by the
first element of the array
sizeof &a size_t n/a total number of bytes used by a
pointer to the array
The expression a
has type "N-element array of T
"; 表达式
a
具有类型“ T
N元素数组”; it is not the operand of the unary &
or sizeof
operators, so it is converted to a pointer to the first element of the array, amd its value is the address of that element. 它不是一元
&
或sizeof
运算符的操作数,因此它被转换为指向数组第一个元素的指针,其值是该元素的地址。
The expression &a
has type "pointer to N-element array of T
"; 表达式
&a
类型为“指向T
N元素数组的指针”; since a
is an operand of the unary &
operator, the conversion rule above isn't applied (which is why the expression has type T (*)[N]
instead of T **
). 由于
a
是一元&
运算符的操作数,因此不应用上面的转换规则(这就是为什么表达式的类型为T (*)[N]
而不是T **
)。 However, since the address of the array is the same as the address of the first element of the array, it yields the same value as the expression a
. 但是,由于数组的地址与数组的第一个元素的地址相同,因此它产生的值与表达式
a
相同。
The expression &a[0]
has type "pointer to T
", and explicitly points to the first element of the array. 表达式
&a[0]
类型为“指向T
指针”,并显式指向数组的第一个元素。 Again, this value will be the same as the previous two expressions. 同样,此值将与前两个表达式相同。
For a 2D array 对于2D阵列
T a[M][N];
all of the following are true: 满足以下所有条件:
Expression Type Decays to Value
---------- ---- --------- -----
a T [M][N] T (*)[N] address of first subarray, a[0]
*a T [N] T * address pf first subarray, a[0]
&a T (*)[M][N] n/a address of the array, which is
the same as the address of the
first subarray, which is the same
as the address of the first element
of the first subarray.
a[i] T [N] T * address of first element of i'th
subarray
*a[i] T n/a value of first element of i'th subarray
&a[i] T (*)[N] n/a address of the i'th subarray
sizeof a size_t n/a total number of bytes used by the
array
sizeof *a size_t n/a total number of bytes used by the
first subarray
sizeof &a size_t n/a total number of bytes used by a
pointer to the array
Final note: to print out pointer values, use the %p
conversion specifier and cast the argument to (void *)
(this is the pretty much the only time it's considered proper to explicitly cast a pointer to void *
): 最后说明:要打印出指针值,请使用
%p
转换说明符,并将参数%p
转换为(void *)
(这是唯一一次将指针显式转换为void *
适当做法):
printf( " &a yields %p\n", (void *) &a );
printf( " a yields %p\n", (void *) a );
printf( "&a[0] yields %p\n", (void *) &a[0] );
Edit 编辑
To answer a question in the comments: 要在评论中回答问题:
num,num[] and num[][] are all different thing.
num,num []和num [] []都是不同的东西。 There types are different.Here num decays and became pointer to a pointer and num[] decays and became pointer to int and num[][] is a int.
类型有所不同。这里num衰减并成为指向指针的指针,num []衰减并成为指向int的指针,而num [] []是一个int。 Right?
对?
Not quite. 不完全的。
Assuming a declaration like 假设一个声明像
int arr[10][10];
then the expression arr
will decay to type int (*)[10]
(pointer to 10-element array of int
), not int **
; 然后表达式
arr
将衰减为int (*)[10]
(指向int
10个元素的数组的指针),而不是int **
; refer to the table above again. 请再次参考上表。 Otherwise you're right;
否则你是对的。
arr[i]
will decay to type int *
, and arr[i][j]
will have type int
. arr[i]
将衰减为int *
类型,而arr[i][j]
将具有int
类型。
An expression of type "N-element array of T
" decays to type "pointer to T
"; “ N个元素的
T
数组”类型的表达式衰减为“ T
指针”类型; if T
is an array type, then the result is "pointer to array", not "pointer to pointer". 如果
T
是数组类型,则结果是“指向数组的指针”,而不是“指向指针的指针”。
In the second example, num
is a 2 dimensional array, or say an array of array. 在第二个示例中,
num
是二维数组,或者说是数组的数组。 It's true that *num
is its first element, but this first element is an array itself. 确实,
*num
是它的第一个元素,但是这个第一个元素是数组本身。
To get num[0][0]
, you need **num
. 要获取
num[0][0]
,您需要**num
。
printf("%d\n", **num);
Look how an array looks like: 看一下数组的样子:
int num[ ] [2]={20,30,40,50};
is better written as 最好写成
int num[][2]={{20,30},{40,50}};
It is an array with 2 elements. 它是一个包含2个元素的数组。 Those 2 elements are, again, arrays with 2 ints.
同样,这2个元素是具有2个int的数组。
In memory, they look like 在内存中,它们看起来像
20 30 40 50
but the difference is that num
refers to the whole array, num[0]
to the first "part- array" and num[0][0]
to the first element of the first array. 但是区别在于
num
指向整个数组, num[0]
指向第一个“部分数组”, num[0][0]
指向第一个数组的第一个元素。
They have the same address (because they start at the same place), but they have a different type. 它们具有相同的地址(因为它们从同一位置开始),但是它们的类型不同。
That is, the address is not the only important thing with a pointer, the type is important as well. 也就是说,地址不是唯一具有指针的重要内容,类型也很重要。
Arrays are not pointers actually, though they tend to act in a bit similar way, but not always. 数组实际上并不是指针,尽管它们往往以类似的方式起作用,但并非总是如此。
Say you have this array and a pointer: 假设您有以下数组和一个指针:
int a[] = {1, 2, 3};
int i = 19;
int *ptr = &i;
Now here a is equal to &a
, but the same is not true, for pointers ( ptr is not equal to &ptr
). 现在,这里的
a is equal to &a
,但是对于指针来说,这是不正确的( ptr is not equal to &ptr
)。
Now coming to the question: 现在来提一个问题:
Consider a single dimensional array: 考虑一维数组:
int arr[] = {11, 19, 5, 9};
Here, this array elements are stored in contiguous memory locations. 在此,此数组元素存储在连续的存储位置中。 Say, with starting address
0
: 说,起始地址为
0
:
---------------------
| 11 | 19 | 5 | 9 |
---------------------
0 4 8 12 16
Now when you write name of the array, arr (for this example), you will get the starting address of the 1 st element. 现在,当您为该示例编写数组名称arr时,您将获得第一个元素的起始地址。 Though if you write
&arr
, then you get the starting address of the whole block(this includes all the elements of the array). 尽管如果您写
&arr
,那么您将获得整个块的起始地址(包括数组的所有元素)。 Now when you write *arr
, you actually get the value inside the 1 st element of this array. 现在,当您编写
*arr
,实际上是在该数组的第一个元素内获取了值。
Now consider this 2-dimensional array arr[][4] = {{11, 19, 5, 9}, {5, 9, 11, 19}}: 现在考虑这个二维数组arr [] [4] = {{11,19,5,9},{5,9,11,19}}:
0 4 8 12 16 -> These are memory addresses
---------------------
| 11 | 19 | 5 | 9 | ----> These values represent the values inside each index
---------------------
| 5 | 9 | 11 | 19 |
---------------------
16 20 24 28 32
Here, when you write the name of the array, as arr
, what you get is the address of the 1 st element of this array, which in this case will be address of this 0 th index: 在这里,当你写的数组名称,
arr
,你得到的是该数组的第一单元,在这种情况下将是这第 0 个索引地址的地址:
0 16 32
----------------------------------------------
| 0<sup>th</sup> index | 1<sup>st</sup> index |
----------------------------------------------
Now when you do &arr
, here what you get is the base address for whole of the block, ie base address of this: 现在,当您执行
&arr
,在这里您获得的是整个块的基地址,即该基地址:
0 4 8 12 16
---------------------
| 11 | 19 | 5 | 9 |
---------------------
| 5 | 9 | 11 | 19 |
---------------------
16 20 24 28 32
Now, if you do *arr
, in 1-dimensional array it gives you the value inside the 1 st element, though in 2-dimensional array, the value inside each index is actually one 1-dimensional array, hence you will get the address of this array: 现在,如果执行
*arr
,则在一维数组中将为您提供第一个元素内的值,尽管在二维数组中,每个索引内的值实际上是一个一维数组,因此您将获得地址该数组的:
0 4 8 12 16
---------------------
| 11 | 19 | 5 | 9 |
---------------------
Now if you do **arr
, that is when you will actually get the value inside the 1 st element, which is 11
. 现在,如果执行
**arr
,则实际上是在第一个元素11
获得值。
I hope it clears some doubts :-) 我希望它消除了一些疑问:-)
EDIT 1: 编辑1:
As brought to my attendtion, by fellow user, it seems there is a bit of a confusion somewhere, though I have explained in detail what is meant by what thingy. 引起用户注意的是,其他用户似乎在某个地方有些困惑,尽管我已经详细解释了什么是什么。 But just to justify, for this statement:
但是,为了证明这一点,请这样做:
Now here __a is equal to &a__, but the same is not true, for pointers (__ptr is not equal to &ptr__).现在,这里的__a等于&a__,但是对于指针(__ptr不等于&ptr__)来说,情况并非如此。
The types of both a
and &a
will be different, as already stated, in the answer. 如前所述,答案中
a
和&a
的类型将有所不同。 If one performs pointer arithmetics, one will able to know that. 如果执行指针算术运算,则将能够知道这一点。 Try performing
a + 1
and &a + 1
, how they both react to pointer arithmetics will surely give a good idea. 尝试执行
a + 1
和&a + 1
,它们对指针算术的反应肯定会提供一个好主意。
Considering a 1-dimensional array: 考虑一维数组:
int arr[] = {11, 19, 5, 9};
---------------------
| 11 | 19 | 5 | 9 |
---------------------
0 4 8 12 16
We cannot do a++
, though for a pointer: 我们不能做
a++
,尽管对于一个指针:
int i = 4;
int *ptr = &i;
we can perform ptr++
, this will make ptr
point to the next memory location. 我们可以执行
ptr++
,这将使ptr
指向下一个内存位置。
I think it result means that the array not really a pointer, but it is converted to a pointer in some contexts that is expected a pointer, like pass to a function that expect a pointer argument. 我认为它的结果意味着该数组不是真正的指针,而是在某些需要指针的上下文中转换为指针,例如传递给需要指针参数的函数。
see this code: 看到下面的代码:
void test(int* num) {
printf("test\n");
printf("%p\n",num);
printf("%p\n",&num);
printf("%p\n",&num[0]);
}
int main(){
int num[2]={20,30};
test(num);
printf("main\n");
printf("%p\n",num);
printf("%p\n",&num);
printf("%p\n",&num[0]);
//other();
return 0;
}
The output is: 输出为:
test
0x7fff7a422300
0x7fff7a4222e8 //LOOK THIS! Is diferent from main!
0x7fff7a422300
main
0x7fff7a422300
0x7fff7a422300
0x7fff7a422300
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.