【问题标题】:sizeof array clarificationsizeof 数组说明
【发布时间】:2011-05-09 06:21:12
【问题描述】:

我正在学习 C 的期末考试,并且有一个关于 sizeof 运算符的问题。

假设int 的大小是32 位,而指针是64 位。

如果有函数:

int
foo (int zap[])
{
    int a = sizeof(zap);
    return a;
}

因为zap 是一个指针,所以foo 将返回8,因为这是存储这个特定指针所需的字节数。但是,使用以下代码:

int zip[] = { 0, 1, 2, 3, 4, 5 };
int i = sizeof(zip);

i 将是 6 * sizeof(int) = 6 * 4 = 24

为什么sizeof(zip) 返回元素的数量乘以每个元素的大小,而sizeof(zap) 返回指针的大小?是不是zap的大小是未指定的,而zip不是?编译器知道zip6 元素,但不知道zap 可能有多大。

【问题讨论】:

    标签: c


    【解决方案1】:

    这是 C 语法中的一种不对称。在 C 语言中,不可能将数组传递给函数,因此当您在函数声明中为某个参数使用数组语法时,编译器会将其作为指针读取。

    在大多数情况下,在 C 语言中,当您在表达式中使用数组时,数组会隐式转换为指向其第一个元素的指针,这正是例如当您调用函数时发生的情况。在以下代码中:

    int bar[] = {1,2,3,4};
    foo(bar);
    

    数组被转换为指向第一个元素的指针,这就是函数接收的内容。

    然而,这种隐式转换规则并不总是适用。正如您所发现的,例如sizeof 运算符适用于数组,甚至&(地址)运算符也适用于原始数组(即sizeof(*&bar) == 4*sizeof(int))。

    C 中的函数不能接收数组作为参数,它只能接收指向第一个元素的指针,或者指向数组的指针...或者您必须将数组包装在结构中。

    即使你在函数声明中的括号内放了一个数字...

    void foo(int x[4])
    {
        ...
    }
    

    编译器完全忽略该数字...编译器的声明完全等同于

    void foo(int *x)
    {
        ...
    }
    

    例如,即使调用它传递一个不同大小的数组也不会触发任何错误...

    int tooshort[] = {1,2,3};
    foo(tooshort);  /* Legal, even if probably wrong */
    

    (实际上编译器MAY会给出警告,但代码是完全合法的C,如果编译器遵循标准则必须接受)

    如果你认为函数参数中关于数组的这条规则很奇怪,那么我同意,但这就是 C 语言的定义方式。

    【讨论】:

    • 数字不会被编译器忽略,int x[4] 作为函数参数意味着你必须传递一个正好个元素的数组指针。这与在代码中的其他地方写 int (*x)[4] 完全相同。除此之外,这个答案指出了问题:参数的数组语法与程序中其他地方声明的数组具有不同的含义。它是 C 语言中比较笨的“特性”之一。为避免混淆,请始终对参数使用 int* x 表示法。
    • 你能指出标准中括号之间的数字必须等于传递数组的大小吗?提示:这将是一个奇怪的要求,因为您根本无法传递数组并且函数实际上只接收一个指针。当使用foo(bar) 调用函数时,其中bar 是一个数组,在考虑函数调用之前,该数组已经被转换为指针即使对于编译器。对已经在转换中删除的尺寸信息施加限制是没有意义的。
    • @Lundin,对于数组参数的第一维,没有 4 基本上被忽略。此外,C99 还可以使用关键字 static 来指定该函数需要 至少 项。但参数的类型仍然是int*
    • 在检查标准 C99 6.7.5.3 §7 之后,数组指针的大小似乎只有在参数声明为静态时才重要。这一切真的很晦涩难懂,我不相信C90有这个“功能”。最佳实践是永远不要将 [] 用于函数参数,这样您就不必怀疑 C 委员会在编写标准的这个特定部分时在吸什么。
    • 谢谢 6502 这对您有很大帮助。
    【解决方案2】:

    因为 zip 是一个数组,编译器在编译时知道它的大小。这只是对两种不同的事物使用相同符号的情况,这在 C 中很常见。

    int
    foo (int zap[])
    

    完全等价于

    int
    foo (int *zap)
    

    编译器不知道 zap 有多大(因此它将找出问题的任务留给了程序员)。

    【讨论】:

    • 即使你在方括号之间放了一个数字,但它仍然只是一个指针,并且数字本身会被编译器完全忽略。所以编译器不知道大小不是问题......它是C语言对函数参数列表中的数组有一个特殊的奇怪规则。
    • @6502 你说得对,好电话。将数字放在括号中将具有相同的效果,这就是强烈建议不要这样做的原因。
    【解决方案3】:

    zip6 * sizeof(int) 的内存块,因此它的大小为 24(在您的架构上)。 zap(它也可以在你的函数声明中写成int *zap)但是可以指向任何内存地址,编译器无法知道从这个(甚至包含这个)地址开始分配了多少空间。

    【讨论】:

      【解决方案4】:

      zip 的大小在编译时是已知的,zap 的大小是未知的。这就是为什么您在sizeof(zap) 上获得指针的大小以及在sizeof(zip) 上获得数组大小的原因。

      【讨论】:

        【解决方案5】:

        在某些情况下,数组会衰减为指针。函数调用就是其中之一。

        【讨论】:

          【解决方案6】:

          因为它已经用 6 个元素进行了静态初始化。

          【讨论】:

          • 有人想澄清否决票?我的答案和其他2个一样,只是更简洁一点??
          • 我没有投反对票,但“zip”是否已初始化并不重要。问题全在于 C 的怪异函数参数语法。
          猜你喜欢
          • 2018-03-25
          • 1970-01-01
          • 2021-04-27
          • 1970-01-01
          • 2021-10-27
          • 1970-01-01
          • 1970-01-01
          • 2020-01-19
          相关资源
          最近更新 更多