简体   繁体   English

* num为什么不显示第零个元素值?

[英]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 ”和表达式的值将是数组第一个元素的地址, 数组表达式为以下之一时除外

  • an operand of the sizeof operator sizeof运算符的操作数
  • an operand of the unary & operator 一元&运算子的运算元
  • an operand of the _Alignof operator (C99 and later) _Alignof运算符的操作数(C99和更高版本)
  • a string literal used to initialize an array in a declaration 用于初始化声明中的数组的字符串文字

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM