代码:
int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;
printf("p:%p\n",p);
printf("*p:%p\n",*p);
结果:p = *p = arr = 0x7ffee517c830
它们都是数组的地址
使用p
访问arr [i]的正确方法是*(*p+i)
指针p
的类型为int(*)[5]
,因此p指向类型为int [5]
的数组。但我们不能说p指向arr
的一个看不见的外壳,p毕竟是一个变量。它存储arr
的地址,arr[0]
也是arr
的第一个元素*p
的地址。
我认为1
会让我arr
,这是p
的第一个元素。
取消引用操作意味着将arr
中的值作为地址,并从该地址获取值。对?
因此,p存储0x7ffee517c830
的地址,此处为1
,**p
存储在此地址中。 1
不是非法的吗?第一次取消引用会向我们提供1
,第二次取消引用会使用P5.Graphics
作为非法的地址。
我缺少什么?
答案 0 :(得分:5)
*p
的结果是数组类型的左值表达式。在您现在可以想到的任何表达式中,使用(*p)
与使用arr
完全相同。
例如:
&*p
表示&arr
**p
表示*arr
(这是合法的)。(*p)[i]
表示arr[i]
。sizeof *p
表示sizeof arr
。阵列在这方面并不特别。您可以使用int x; int *q = &x;
看到相同的现象。现在*q
和x
具有完全相同的含义。
关于你的最后一段,我认为通过将指针想象成美化的整数,你会让自己感到困惑。有些人用这种方式教指针,但是IMO并不是一种好的教学技巧,因为它会导致你现在感到困惑。
如果您取消引用int(*)[5]
,则会获得int[5]
,而这就是它的全部内容。数据类型在解除引用时很重要。谈论“解除引用0x7ffee517c830
”是没有意义的。同样,这并不是数组所特有的;如果您取消引用char ***
,则会获得char **
等。
在本讨论中数组“不同”的唯一方法是,如果您尝试对它们进行算术运算,或输出它们等,会发生什么情况。例如,如果您提供int[5]
作为printf参数,隐含转换为int *
指向这5个整数中的第一个。将*
运算符应用于int[5]
时也会发生此转换,这就是为什么你会得到int
的原因。
答案 1 :(得分:2)
p
被声明为'指向int [5]'的指针。
arr
被声明为'int [5]`
所以初始化程序p = &arr;
并不是那么奇怪。如果你用int[5]
取代任何原始类型,你就不会睁大眼睛。
*p
是arr的另一个句柄。所以(* p)[0] = 1。
这真的只出现在奇怪的情况下。使用下标运算符取消引用指向数组的指针是最自然的。这是一个人为的例子,我想传递一个表作为参数。
#include <stdio.h>
int print_row_range(int (*tab) [2], int first, int last)
{
int i;
for(i=first; i<= last; i++)
{
printf("{%d, %d}\n", tab[i][0], tab[i][1]);
}
}
int main(int argc, char *argv[])
{
int arr[3][2] = {{1,2},{3,4},{5,6}};
print_row_range(arr,1,2);
}
此示例将表视为行数组。
答案 2 :(得分:0)
解除引用不会为您提供值。它为您提供了一个对象,如果可以转换为它,可以将其用作其类型的值。
与*p
相同的 arr
是5个整数数组的对象,因此如果您想从数组中获取整数,您必须再取消引用,例如(*p)[3]
。
考虑一个更大的例子:
int arr[5][5];
int (*p)[5] = arr;
现在你得到arr[0]
*p
,它本身是一个5的数组。差别就是这样:
*( p+1) == arr[1];
*(*p+1) == arr[0][1];
^ ^^^
明白了吗?
答案 3 :(得分:0)
一个用例是能够使用malloc分配只有一个malloc的2D(或更多)数组指针:
#include <stdio.h>
#include <stdlib.h>
static int (*foo(size_t n))[42] {
return malloc(sizeof *foo(0) * n);
// return malloc(sizeof(int [n][42]); works too
}
int main(void) {
size_t n = 42;
int (*p)[42] = foo(n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}
我觉得这很有趣。
VLA还有一个:
#include <stdio.h>
#include <stdlib.h>
static void *foo(size_t elem, size_t n, size_t m) {
return malloc(elem * n * m);
}
int main(void) {
size_t n = 42;
int (*p)[n] = foo(sizeof **p, n, n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}