我在学习C语言中的数组和指针时感到困惑,为什么ch,& ch,& ch [0]恰好彼此相等,而sptr,& sptr,& sptr [0]不是? 这是我的源代码:
int main(void)
{
char ch[7] = { '1','2','3','4','5','6','0' };
char *sptr = "132456";
double db[4] = { 1.0,2.0,3.0,4.0 };
printf("\n%p %p %p\n", ch, &ch,&ch[0]);
printf("\n%p %p %p\n", sptr, &sptr,&sptr[0]);
printf("\n%p %p %p\n", db, &db,&db[0]);
return 0;
}
我机器上的输入是:
00FDFD68 00FDFD68 00FDFD68
00037CD0 00FDFD5C 00037CD0
00FDFD34 00FDFD34 00FDFD34
答案 0 :(得分:6)
在大多数(虽然不是全部)上下文中,数组"衰变"到指向其第一个元素的指针。这就是为什么ch
和&ch[0]
在您的示例中是相同的(数组元素访问的优先级高于""运算符的地址,因此后者也可以写为{{ 1}})。
剩下的&(ch[0])
是一个数组不会衰减成指针的情况;相反,你得到了数组的地址。当然,这与数组的第一个元素的地址相同 - 但是,重要的是,它具有不同的类型;它的类型为&ch
,即指向具有7个元素的char数组的指针。其他两个指针的类型为char (*)[7]
,即指向个人char *
的指针。
由于char
是一个指针,sptr
是该指针的地址,自然会有所不同。 &sptr
相当于&sptr[0]
,当然等于sptr + 0
。
您不明白为什么sptr
和sptr
会产生不同的地址,这表明对指针的误解。指针是一个固定大小的对象,其值可以引用(指向)特定类型的某个任意对象。因为它本身就是一个对象,所以可以使指针指向不同的对象。另一方面,数组变量始终(在其生命周期内)引用相同的数组对象。
在您的示例输出中:
&sptr
第一个值00037CD0是00037CD0 00FDFD5C 00037CD0
指向的位置 - 也就是说,它是字符串常量" 132456"的内存位置。第二个值00FDFD5C是sptr
变量本身的地址。这表明地址为00FDFD5C的指针对象保存了值00037CD0。
基本上,两种情况之间的区别归结为:
答案 1 :(得分:3)
如果我们"画"它出来了,你的数组ch
在内存中看起来像这样:
+-----+-----+-----+-----+-----+-----+-----+ | '1' | '2' | '3' | '4' | '5' | '6' | '0' | +-----+-----+-----+-----+-----+-----+-----+ ^ ^ | | | &ch[1] | &ch ^ | &ch[0]
正如您所看到的,&ch
和&ch[0]
都指向同一位置。但是这两个表达式之间存在重要差异:&ch
是指向数组的指针,而&ch[0]
是指向元素的指针阵列。这两个指针有不同的类型:&ch
的类型为char (*)[7]
,而&ch[0]
的类型为char *
。即使两者都是指向同一位置的指针,类型的差异也会使它在语义上非常不同。
现在array
如何适应这一切。对于任何数组或指针a
和索引i
,表达式a[i]
等于*(a + i)
。这意味着&a[i]
等于&*(a + i)
。地址和解除引用运算符相互抵消,这意味着&a[i]
等于(a + i)
。如果索引为零,我们&a[0]
等于(a + 0)
,但由于将no添加为0是no-op,它也等于(a)
,等于a
}。因此&a[0]
等于a
。当你看到有人说数组衰减指向第一个元素的指针时,这就是他们的意思。在表达式中使用数组a
与使用&a[0]
相同。
在一个不相关的注释中,数组ch
可能是一个字符数组,但它不是一个字符串。这是因为在C字符串中实际上称为 null终止字符串。单词" null"在这种情况下,不是空指针,而是整数(非字符)零。
这意味着您不能将ch
用于任何需要字符串的函数,因为这会导致未定义的行为,因为这些函数会越界寻找终结符。