C语言中数组,&数组和&数组[0]之间有什么区别?

时间:2017-04-21 12:12:01

标签: c arrays pointers

我在学习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

2 个答案:

答案 0 :(得分:6)

在大多数(虽然不是全部)上下文中,数组"衰变"到指向其第一个元素的指针。这就是为什么ch&ch[0]在您的示例中是相同的(数组元素访问的优先级高于""运算符的地址,因此后者也可以写为{{ 1}})。

剩下的&(ch[0])是一个数组不会衰减成指针的情况;相反,你得到了数组的地址。当然,这与数组的第一个元素的地址相同 - 但是,重要的是,它具有不同的类型;它的类型为&ch,即指向具有7个元素的char数组的指针。其他两个指针的类型为char (*)[7],即指向个人char *的指针。

由于char是一个指针,sptr是该指针的地址,自然会有所不同。 &sptr相当于&sptr[0],当然等于sptr + 0

您不明白为什么sptrsptr会产生不同的地址,这表明对指针的误解。指针是一个固定大小的对象,其值可以引用(指向)特定类型的某个任意对象。因为它本身就是一个对象,所以可以使指针指向不同的对象。另一方面,数组变量始终(在其生命周期内)引用相同的数组对象。

在您的示例输出中:

&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用于任何需要字符串的函数,因为这会导致未定义的行为,因为这些函数会越界寻找终结符。