【问题标题】:Does nth index of n sized C array contain size of it?n 个大小的 C 数组的第 n 个索引是否包含它的大小?
【发布时间】:2015-10-07 20:27:55
【问题描述】:

我编写了一个 C 程序,用于使用指针显示数组的值。这是代码:

#include <stdio.h>

int main()
{
    int a[] = {1, 1, 1, 1, 1};
    int *ptr = a;
    for (int i = 0 ; i < 5; i++)
        printf("%d ", *ptr++);
    printf("%d", *ptr);
}

正如您在终止循环后所看到的,指针保存了数组外某个值的内存地址。因为它,即最后一个输出没有初始化,它应该是一个垃圾值。但是,每次它显示 5 这是数组的大小。然后,我认为数组分配内存的下一个内存地址包含数组的大小。但是,双类型数组不会发生这种情况。

Output for int array : 1 1 1 1 1 5
Output for double array : 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 

有人解释一下输出吗?

【问题讨论】:

  • 您正在使用 i++,因此 ptr 指向数组 a 之外的程序内存中的一个区域。由于您重新编译以从 int 更改为 double 我无法推断为什么在一种情况下您得到 5 而另一种情况下得到零。 double 和 int 都存储为 4 个字节,double 是 IEEE 488 浮点数。
  • @jdweng: 1) 进一步研究未定义的行为是没有用的。 2) double 至少需要 64 位,即 8 个八位字节(除非您的字节有 16 位,这将是完全有效的 - 检查 CHAR_BIT) 3) 什么是 IEEE488?通常 C 使用 IEC 60559(又名 IEEE754)浮点。永远不要标题你提到的标准。能给个链接吗?
  • "它应该是一个垃圾值" -- 它一个垃圾值。 "但是,每次它都显示 5,这是数组的大小。' -- 5 是垃圾。垃圾不需要每次都具有不同的值;看起来一致的垃圾仍然是垃圾。垃圾不是(必然)随机的。
  • 很可能是跑到i的低位字节了,刚好在数组后面存入内存,循环后应该是5。
  • 我写错了 IEEE 规范。对不起。

标签: c arrays pointers garbage


【解决方案1】:

这只是该地址中内存中的一个值。您永远不应该访问不是由您分配的内存(在这种情况下,您正在访问第 6 个元素,但您只声明了 5 个)。在某些情况下,这可能会导致分段错误。

【讨论】:

  • 在某些情况下会出现分段错误 -> 不受约束的行为
  • 不能只是内存地址的值。我已经运行了 20 多次代码。我已经多次重新启动 Code Blocks IDE。重新启动计算机。更改了数组的大小。而且我仍然得到第 n 个位置的大小。
  • 还是巧合。
  • 操作系统对内存管理做了很多优化。所以很有可能每次你都会收到相同的内存。
【解决方案2】:

C 不会在任何地方存储任何数组元数据(包括数组长度),无论是在数组的开头还是结尾。对于整数数组,最有可能的解释是变量i使用的内存紧跟数组的最后一个元素,如下所示:

   +---+
a: | 1 | a[0]
   +---+ 
   | 1 | a[1]
   +---+
   | 1 | a[2]
   +---+
   | 1 | a[3]
   +---+
   | 1 | a[4]
   +---+
i: | 5 | a[5]
   +---+

但是,您不能依赖于这种一致的行为,正如您在将数组类型更改为double 时看到的那样。

尝试读取数组末尾后一元素中包含的值会导致未定义的行为Chapter and (truncated) verse:

6.5.6 加法运算符
...
8 当具有整数类型的表达式被添加到指针或从指针中减去时, 结果具有指针操作数的类型...如果结果指向数组对象的最后一个元素,则它 不得用作被评估的一元 * 运算符的操作数。

为了傻笑,我在工作时在我的系统上编译了你的代码,我得到了以下输出:

1 1 1 1 1 0

这实际上只是编译器如何为这个特定程序在内存中布置对象的人工制品。

【讨论】:

    【解决方案3】:

    你所做的会调用未定义的行为

    简单的巧合,可能只是i的值,打印i的地址并检查。但要小心,它不会总是这样。只需在程序中声明一个新变量,它可能会改变。

    double 的情况下它不起作用,因为数组后面的地址不再匹配i 的地址。我说小心就是这个意思。

    【讨论】:

    • 这不可能只是巧合。我已经运行了 20 多次代码。我已经多次重新启动 Code Blocks IDE。重新启动计算机。更改了数组的大小。而且我仍然得到第 n 个位置的大小。
    • 它取决于程序的堆栈内存,它不会因为你重新编译它或因为你改变数组的大小而改变,但是如果你改变程序它会改变,尝试声明一个在for 循环之前新的int 变量,并给它一个不同于5 的随机值。或者使用不同的编译器。
    • @ParvezMRobin:这是编译器如何为此特定程序在堆栈上排列对象的工件。您的特定变量集合恰好以(看起来)i 跟随数组的最后一个元素的方式排列。不同的编译器或具有不同优化设置的相同编译器可能会以不同的顺序排列变量。这不是一个明确的行为,它真的只是一个巧合。
    • 是的。打印 i 的内存地址不起作用,因为它显示了不同的内存地址。但是当我将代码更改为以下 #include int main() { int a[] = {1, 1, 1, 1, 1}; int *ptr = a; for(int i = 5; i
    • 是的,地址可能不同,请参阅this comment。但想法是它必须让你在内存中布局程序,所以你现在明白了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-25
    • 1970-01-01
    • 2016-03-27
    相关资源
    最近更新 更多