【问题标题】:Why sizes of an array and a pointer to a first element are different?为什么数组的大小和指向第一个元素的指针不同?
【发布时间】:2015-08-19 15:38:08
【问题描述】:

Kernighan & Ritchie 第二版。说:

索引和指针运算的对应关系非常密切。根据定义,数组类型的变量或表达式的值是数组元素零的地址。因此分配后
pa = &a[0];

paa 具有相同的值。 由于数组的名称是初始元素位置的同义词,因此赋值 pa=&a[0] 也可以写为
pa = a;

如果apa 相同,那么为什么是这个代码:

#include <stdio.h>

int main()
{
    char a[] = "hello";
    char *pa = a;
    printf("Array: %ld\n", sizeof(a));
    printf("Pointer: %ld\n", sizeof(pa));
}

输出这个:

Array: 6
Pointer: 8

参考权威来源将不胜感激。

【问题讨论】:

    标签: c arrays pointers


    【解决方案1】:

    两个对象可以有相同的地址,但它们的大小可以不同。

    来自 C 标准(6.5.3.4 sizeof 和 alignof 运算符)

    2 sizeof 运算符产生其操作数的大小(以字节为单位),即 可以是表达式或类型的括号名称。 尺寸为 根据操作数的类型确定....

    考虑以下示例

    #include <stdio.h>
    
    int main( void )
    {
        struct A
        {
            char c;
            int x;
        } a;
    
        printf( "object a:\taddress - %p size - %zu\n",
                &a, sizeof( a ) );
        printf( "object a.c:\taddress - %p size - %zu\n",
                &a.c, sizeof( a.c ) );
    }    
    

    程序输出是

    object a:   address - 0x7fff164e16d0 size - 8
    object a.c: address - 0x7fff164e16d0 size - 1
    

    可以看出struct A 类型的对象a 及其char 类型的数据成员c 具有相同的地址但大小不同。

    对于数组,指针是一个存储其他对象地址的对象。要存储其他对象的地址,根据使用的系统为指针分配例如 4 或 8 个字节的内存就足够了。

    对于数组,它们被命名为内存范围。数组不存储地址。它们存储自己的元素(当然也可以是指针)。

    表达式中使用的数组名被转换为指向其第一个元素的指针。

    根据 C 标准(6.3.2.1 左值、数组和函数指示符)

    3 除非它是 sizeof 运算符的操作数或一元 & 运算符,或者是用于初始化数组的字符串文字,an 具有“类型数组”类型的表达式被转换为 类型为“类型指针”的表达式,指向初始 数组对象的元素并且不是左值。如果数组对象 有注册存储类,行为未定义。

    在此引用中,列出了数组未转换为指向其第一个元素的指针的情况。例如,当数组是sizeof 运算符的操作数时。

    如果要返回你的程序

    int main()
    {
        char a[] = "hello";
        char *pa = a;
        printf("Array: %ld\n", sizeof(a));
        printf("Pointer: %ld\n", sizeof(pa));
    }
    

    那么在这个语句中

        char a[] = "hello";
    

    类型为char[6] 的字符串文字"Hello" 不会转换为指针。 然而在这个声明中

        char *pa = a;
    

    数组a 被转换为指向其第一个元素的指针。

    在此声明中

        printf("Array: %ld\n", sizeof(a));
    

    数组a 未转换为指针,因为它是sizeof 运算符的操作数。

    但是,如果您在 sizeof 运算符中使用了表达式,例如这样

    sizeof( a + 0 )
    

    然后你会得到一个指针,相应地sizeof 会返回指针的大小而不是数组的大小

    【讨论】:

      【解决方案2】:

      它们确实具有相同的。但这并不意味着它们是同一个东西。

      a 仍然是一个固定大小的数组。 pa仍然是一个指针。

      sizeof 是一个认识到这种差异的运营商。

      您的数组有 6 个大小为 char 的元素(sizeof(char) 被标准定义为 1)。 (第 6 个元素是字符串空终止符)。

      sizeof(char*) 在您的系统上是 8。它可能是 64 位的。

      【讨论】:

      • 详细信息:“它们确实具有相同的值” 不同意 paa 具有相同的值。 IMO,a[] 有 6 个char 。在char *pa = a; 的上下文中,表达式a 被转换为具有a 初始元素值的char *,并分配给pa。然而a 没有指针的值。
      • 我知道你在说什么,但我说 是相等的,尽管 类型 不同。
      【解决方案3】:

      数组不是指针。在许多情况下,数组名称​​衰减指向其第一个元素的指针,但sizeof 是少数例外之一。

      C11 §6.3.2.1 左值、数组和函数指示符

      除非它是sizeof 运算符、_Alignof 运算符或一元&amp; 运算符的操作数,或者是用于初始化数组的字符串字面量,否则表达式类型为“array of type " 转换为类型为 "pointer to type" 的表达式,它指向数组对象的初始元素,并且不是左值。

      【讨论】:

      • _Alignof 应该不在例外列表中!
      • @hacks 来源?我引用了标准草案。
      • 这是标准中的一个错误。看看 C11 标准是怎么说的:_Alignof 运算符产生其操作数类型的对齐要求。不计算操作数,结果是一个整数常量。 应用于数组类型时,结果是元素类型的对齐要求 (6.5.3.4 p3)。
      【解决方案4】:
       char a[] = "hello";
       char *pa = a;
      

      这里sizeof(a) 将给出数组a 的大小。而sizeof(pa) 将给出指针pa 的大小。两者都是不同的。

      同样在函数参数数组中衰减为指针,但这个与&amp;一起是例外。

      此外,在打印类型 size_t 时,您应该使用说明符 %zu(在 ANSI C99 中指定)。

      【讨论】:

        【解决方案5】:

        apa 不相同。永远记住:数组不是指针。在表达式中使用时,数组将转换为指向其第一个元素的指针,但有一些例外,包括作为sizeof 运算符的操作数。
        sizeof(a) 将给出数组的大小,而sizeof(pa) 将给出指针的大小。

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多