【问题标题】:C array index and accessing out of bounds [duplicate]C数组索引和访问越界[重复]
【发布时间】:2018-01-03 06:24:25
【问题描述】:

所以我有一个程序

#include "main.h"
#import <limits.h>
#import <stdint.h>

int foo(const void *src, void *dst, uint16_t len)
{
    uint16_t index;
    const uint8_t *srcRef = src;
    uint8_t *dstRef = dst;

    for(index = 0; index <= len; index++)
    {
        dstRef[index] = srcRef[index];
        printf("-> %d - %d\n", index, srcRef[index]);
    }
    printf("%d\n", index);
    return 0;
}

int main()
{
    printf("max length of UInt16 is : %d\n", UINT16_MAX);
    uint8_t arrOr[55];
    uint8_t arr[55];
    arrOr[54] = 7;
    uint16_t len = 119;
    foo(arrOr, arr, len);
    return 0;
}

程序能够越界访问数组索引是否正常? (我实际上期待它崩溃) 当数组长度为55时,最多可以访问119(120崩溃)。

到了 56 时,我仍然只能访问 119 和 120 崩溃它

当它是 57 时,我最多可以访问 135 和 136 崩溃它。

我猜它试图访问分配给整个程序的内存地址,而不仅仅是数组索引。但是当我将数组长度更改为 57 时实际发生了什么,这让我可以访问更多地址,而将其增加到 56 则无法访问?

【问题讨论】:

  • 请调整您的代码,使其不会包含不适合专业话语的词语。
  • #import &lt;stdint.h&gt; ?
  • 您确定这是您编译的确切代码吗?我认为这不会在没有错误的情况下编译。
  • 等等...#import 是什么黑客? Visual Studio 2017 风格?
  • 在你问这个问题之前,问问自己这在哪里有用?为什么你会访问超出你的数组边界?

标签: c arrays pointers memory


【解决方案1】:

看起来对齐很重要。

首先,这是undefined behavior,所以不要依赖它。根据ISO C标准,越界访问是UB。

再次警告:以下内容高度依赖于实现。请自行决定。


好吧,先回答。你猜对了:

我猜它试图访问分配给整个程序的内存地址,而不仅仅是数组索引。

有趣的是,您的数字 120136 相差 16,所以我猜这是由 8 对齐引起的(您有 2 个数组)。在现代计算机中,内存中的数据出于性能考虑而对齐。对于典型的 64 位系统,它与 8 对齐,因此您的数组 arrarrOr 都与 8 字节对齐。也就是说,当您声明大小为 57 时,它实际上占用了 64 字节的内存(因此,如果您声明一个介于 57 和 64 之间的大小,您不会观察到任何差异,但如果它是 65,您会发现)。

对于大于 64 的额外空间,可能是因为调用堆栈。这意味着您正在访问父函数中的变量,例如 mainWinMain 或以上任何内容。当你的程序启动时,系统定义了一些变量(hInstancecommandLinehPrevInstance 等等,在 Windows 上)。当您访问甚至修改这些内存区域时,您就有可能破坏您的程序甚至整个系统。这也是越界访问不好的原因之一。

最后一行(允许我重复注释,因为它很重要),这是依赖于实现的,并且当您在另一个平台上编译代码时可能会发生变化,甚至是同一平台的不同版本。

顺便说一句,#import 不是标准预处理器指示。它(很可能)仅适用于in Visual Studio 2017。以后不要那样做。我猜你正在基于该代码在 Windows 上使用 VS 2017。

【讨论】:

  • 在这些问题上,我们不应该只说 UB。除了 UB 之外,了解计算机或特定操作系统的工作原理也很重要。
  • LONG_BIT 确实是 64(所以一个单词应该是 8 个字节,就像你说的那样)。所以你说的是我的每个数组都使用了一个新词,对吧?考虑到每个数组元素占用 8 位,它确实有意义。这种对齐/填充编译器是否依赖?
  • @LordStiltskin 数组占用 8 的倍数的空间。这并不意味着每个元素占用 8 个字节。相反,8 个元素共享同一个 8 字节字。如果元素少于 8 个,则填充将填充该空间,最多为 8 的倍数。
  • 关于#import,我是在xcode上做的。其实没什么大不了的。我不会使用#import,除非它仅用于 xcode。很抱歉,如果它引起了混乱。另外,如果您有内存填充、对齐等资源,请链接我。有什么工具可以用来检查内存(以图形方式)吗?非常感谢您的实际回复。其他人只是一直忽略真正的问题。他们从来没有得到问题背后的真正想法,tbh
【解决方案2】:

你定义的数组和索引是

uint8_t arrOr[55];

uint8_t arr[55];

索引 = 119;

这是超出数组的,因此您需要减少索引值或增加数组大小,以便访问内存位置值不足,即垃圾或一些时间分段错误

// accessing array out of bounds
#include <stdio.h>
int main()
{
    int arr[] = {1,2,3,4,5};
    printf("arr [0] is %d\n",arr[0]);
    printf("arr[10] is %d\n",arr[10]);
     
    // allocation memory to out of bound 
    // element
    arr[10] = 11;
    printf("arr[10] is %d\n",arr[10]);
    return 0;
}

输出:运行时错误:分段错误 (SIGSEGV)

要点:

-在 C 编程中保持在数组的范围内,同时使用数组来避免任何此类错误。 但是 -C++ 提供了 std::vector 类模板,它不需要执行边界检查。向量还具有 std::at() 成员函数,可以执行边界检查。

在 java 的情况下,您可以使用轻松处理此异常

java.lang.ArrayIndexOutOfBoundsException

【讨论】:

  • 你错过了这个问题。我的问题清楚地表明我知道我不应该故意访问这样的内存。
猜你喜欢
  • 1970-01-01
  • 2015-06-28
  • 2014-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-13
  • 2013-07-27
相关资源
最近更新 更多