编辑 这不是关于“char [1]”和“char *”的数组衰减的问题。我知道一维数组的数组衰减是什么。然而,“char [1][1]”和“char **”似乎不同,因为它们甚至不是兼容的类型。
我知道我可以从“char [1]”和“char *”类型之一转换为另一种类型。然而,“char [1][1]”和“char **”似乎并不那么容易。
在我的主要功能中我有
int main(void) {
char a[1][1];
a[0][0] = 'q';
printf("a: %p\n", a);
printf("*a: %p\n", *a);
printf("**a: %p\n", **a);
}
我当然在编译时带有警告,并且我知道 gcc 抱怨第 6 行,因为 **a 实际上是 char 类型而不是指针类型。然而,运行代码显示“a”和“*a”实际上是相同的指针,但“**a”正如预期的那样是其他东西(我认为0x71在某种程度上与“q”相关)。
我试图理解这一点,似乎因为 *a 和 a 相等 **a 也必须等于 a 因为 **a=*(*a)=*(a)=*a=a 。看来这个推理中唯一的错误可能是 a、*a、**a 的类型。
“a”实际上是如何存储在内存中的?如果“a”是指向另一个内存位置的指针(在我的例子中是 0x7fff9841f250),那么 *a 肯定应该是该内存地址处的值,在我的例子中也是 0x7fff9841f250。那么 **a 将是 0x7fff9841f250 处的值,它与“a”的值相同...似乎我无法以有意义的方式将二维数组“char a[1][1]”视为指针。但我怎么能想到这种类型呢?类型是什么?a、*a、**a、a[0]、a[0][0] 的实际含义是什么?
我已经看到了不兼容的指针类型,但它没有解释操作 *a、**a、a[0]、a[0][0] 实际上在做什么。
您声明了一个二维数组
char a[1][1];
数组
a
的元素具有类型 char[1]
。
在
*a
这样的表达式中,数组指示符是i,显式转换为指向其第一个元素的char ( * )[1]
类型的指针。取消引用指针表达式,您将获得类型为 char[1]
的第一个(并且根据声明为单个)元素。如果像**a
那样再次取消引用表达式,char[1]
类型的表达式会再次转换为指向其第一个元素的char *
类型的指针。因此,表达式 **s
根据分配生成具有 char 类型和值
'q'
的数组的第一个(单个)“行”的第一个字符。
a[0][0] = 'q';
根据 C 标准,表达式
a[0][0]
的计算方式类似于 *( *( a + 0 ) + 0 )
,与 **a
相同
C 标准(6.5.2.1 数组下标):
2 后缀表达式,后跟方括号 [] 中的表达式 是数组对象元素的下标名称。这 下标运算符 [] 的定义是 E1[E2] 等于 (*((E1)+(E2)))。由于适用于的转换规则 二元 + 运算符,如果 E1 是一个数组对象(相当于一个指针 到数组对象的初始元素)并且 E2 是一个整数, E1[E2]表示E1的第E2个元素(从零开始计数)。
所以声明
a[0][0] = 'q';
可能会重写为
**a = 'q';
在 printf 的调用中
printf("a: %p\n", a);
最好重写为
printf("a: %p\n", ( void * )a);
具有类型 a
的
char[1][1]
表达式被隐式转换为指向
char[1]
类型的第一个元素(具有类型
char ( * )[1]
)的指针,并产生数组占用的内存范围的起始地址.在 printf 的调用中
printf("*a: %p\n", *a);
再次应该重写为
printf("*a: %p\n", ( void * )*a);
具有数组类型 *a
的表达式
char[1]
隐式转换为类型为
char *
的第一个元素的指针,并产生相同的地址,因为元素
a[0]
和
a[0[0]
位于相同的地址。printf 的这个调用
printf("**a: %p\n", **a);
不正确,因为字符(ezpresson **a
的类型)被作为地址输出。