简体   繁体   English

指向整数数组的指针与指向整数的双指针

[英]Pointer to Integer Array versus Double Pointer to Integer

I would have thought that an integer array is of type pointer to integer, so that would mean that a pointer to an integer array is of type double pointer to integer. 我原以为整数数组是指向整数的类型指针,因此这意味着指向整数数组的指针是指向整数的双指针。 But the results that I am getting say otherwise. 但我得到的结果却不然。 I have suspicion that the type integer array is not of type pointer to integer. 我怀疑类型整数数组不是指向整数的类型指针。

Here is my example: 这是我的例子:

int main(){
  int p[3]={1,2,3};
  int (*ptr)[3] = &p;
  int **ptr2 = &p;

  printf("%d\n",(*ptr)[0]);
  printf("%d\n",**ptr2);
  return 0;
}

p is of type 3 element integer array. p是3类元素整数数组。

&p is of type pointer to 3 element integer array. &p是指向3个元素整数数组的类型指针。

ptr is of type pointer to 3 element integer array. ptr是指向3个元素整数数组的类型指针。

ptr2 is of type double pointer to integer ptr2是指向整数的双指针

So my question is, if an integer array is a pointer to integer, why doesn't ptr2 work as expected? 所以我的问题是,如果整数数组是指向整数的指针,为什么ptr2不按预期工作? Is the type double pointer to integer different from the type pointer to integer array? 类型指针指向整数数组的类型指针是否为double? Any help clearing this up for me would be appreciated. 任何帮助为我清除这一点将不胜感激。 Thank you! 谢谢!

While the innermost dimension of a multidimensional array in C readily converts to a pointer: 虽然C中多维数组的最内层维度很容易转换为指针:

char (*p)[2][3][4]= //<pointer to an array of 2 or array of 3 of array of 4 char
    (char[5/*<- this one decays to a ptr*/][2][3][4]){0};
    //^array 5 of array 2 of arry 3 of array 4 of char
    ;

arrays and pointers are very different in C despite the confusingly identical syntax for indexing and dereferencing (which are both two sides of the same coin as: x[index] is the same as *(x+index) or index[x] ). 数组和指针在C中是非常不同的,尽管索引和解除引用的语法混淆相同(它们都是同一个硬币的两面: x[index]*(x+index)index[x] )。

I think this is a part of C where if you don't have context, the idea that the language maps directly to assembly breaks down most apparently. 我认为这是C的一部分,如果你没有上下文,语言直接映射到汇编的想法最明显。

Compare 相比

char a[1][1][1][1]={{{{'a'}}}}; //1 byte
char ****b = &(char***){&(char**){&(char*){&(char){'b'}}}}; //1byte+4*ptr_sz

and now the code that ****a generates vs what ****b generates : 现在****a生成的代码****b生成的代码:

char get_a_char(void)
{
    return ****a;
}
char get_b_char(void)
{
    return ****b;
}

x86-64: X86-64:

get_a_char:
        mov     al, BYTE PTR a[rip]
        ret
get_b_char:
        mov     rax, QWORD PTR b[rip]
        mov     rax, QWORD PTR [rax]
        mov     rax, QWORD PTR [rax]
        mov     rax, QWORD PTR [rax]
        mov     al, BYTE PTR [rax]
        ret

When you dereference a multiply indirect pointer ( b ), you get a pointer chase. 当您取消引用乘法间接指针( b )时,您将获得指针追踪。

When you dereference/subscript a multidimensional array, then your subscripts (zeros if you're just dereferencing) and the dimensions of the array are used to calculate an offset from a base, so you eventually either get an offsetted pointer (the same pointer if you're just derefing, just with a different type) if you deref/subscript through just some of the dimensions, or the same followed by a fetch from that address if you deref/subscript through all of them. 当您取消引用/下标多维数组时,您的下标(如果您只是解除引用则为零)和数组的维度用于计算从基数的偏移量,因此您最终要么得到一个偏移指针(如果您使用相同的指针)如果你通过一些维度deref /下标,或者如果你通过所有维度deref /下标,那么你只需要从那个地址取一个,你只是在derefing,只是使用不同的类型。

In your case ptr is int (*)[3] -- a pointer to an array of 3 int but ptr2 is int** -- a pointer to a pointer to int. 在你的情况下, ptrint (*)[3] - 指向3 int数组的指针,但ptr2int** - 指向int的指针。

When you do ptr2[1][2] you add 1 pointer size, fetch a pointer from there, and then add 2 int (target type) sizes to the fetched pointer and fetch from there. 当您执行ptr2[1][2] ,添加1个指针大小,从那里获取指针,然后将2个int(目标类型)大小添加到获取的指针并从那里获取。

That's very different from when you do ptr[1][2] in which case you add one int[3] size to the base pointer and then 2 int sizes and fetch from there (a total of 1 fetch). 这与你执行ptr[1][2]时的情况非常不同,在这种情况下,你将一个int[3]大小添加到基指针,然后添加2个int大小并从那里获取(总共1次获取)。

The types of ptr obviously cannot be compatible with the type of ptr2 . ptr的类型显然不能与ptr2的类型兼容。

I would have thought that an integer array is of type pointer to integer, 我原以为整数数组是指向整数的类型指针,

It is not. 它不是。 Arrays decays to pointers in many common circumstances, but they are not the same. 在许多常见情况下,数组衰减指针,但它们并不相同。

so that would mean that a pointer to an integer array is of type double pointer to integer. 这意味着指向整数数组的指针是指向整数的双指针。

No it is not. 不它不是。

why doesn't ptr2 work as expected? 为什么ptr2没有按预期工作?

ptr2 is a pointer that contains the address of the array p . ptr2是一个包含数组p地址的指针。 Dereferencing this with *ptr2 would give the first element in p . *ptr2取消引用它将给出p的第一个元素。 Dereferencing this again would use the first element in p as an address, and give the value at that address. 再次取消引用它将使用p的第一个元素作为地址,并在该地址处给出值。

This is why you should read the warnings from your compiler. 这就是您应该阅读编译器警告的原因。 Even without the flags -Wall and -Wextra (which you always should use) this code emits this warning: 即使没有标志-Wall-Wextra (你总是应该使用),这段代码会发出以下警告:

k.c:6:16: warning: initialization of ‘int **’ from incompatible pointer type ‘int (*)[3]’ [-Wincompatible-pointer-types]
   int **ptr2 = &p;
                ^

There you have it in plain text. 你有纯文本。 int ** is not compatible with int(*)[3] int **int(*)[3]不兼容

Always read compiler warnings. 始终阅读编译器警告。

As you have discovered, you can take the address of an array. 如您所发现,您可以获取数组的地址。 the type of that is a generally not very useful "pointer to specific array type", not a generic pointer to pointer to content. 它的类型通常不是非常有用的“指向特定数组类型的指针”,而不是指向内容指针的通用指针。

If you must, you can create a pointer that is equivalent to the array, and then take the address of that: 如果必须,可以创建一个与数组等效的指针,然后获取该地址:

int p[] = {1,2,3};
int *q=p;
int **r=q;

But there is no way to shortcut this step, and you are dependent on the lifetime of that intermediate pointer. 但是没有办法快捷这一步,你依赖于那个中间指针的生命周期。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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