【问题标题】:Array overflow (why does this work?) [duplicate]数组溢出(为什么会这样?)[重复]
【发布时间】:2012-04-20 13:28:16
【问题描述】:

好的,所以我正在教我的女朋友一些 c++,她写了一个我认为行不通的程序,但它确实有效。它访问数组中的另一个元素(例如,访问数组 [5] 以获取大小为 5 的数组)。这是缓冲区溢出的实例吗?我的想法是它直接在数组之后写入/访问内存,这是正确的吗?基本上我的问题是..为什么这行得通?

#include <iostream>

using namespace std;

int main()
{
int size;

cout << "Please enter a size for the array." << endl;
cin >> size;
cout << endl;

cout << "There are " << size << " elements in this array." << endl;
cout << endl;
cout << endl;
cout << endl;

int array[size];

for (int counter = 1; counter <= size; counter++)

{
    cout << "Please enter a value for element " << counter << "." << endl;
    cin >> array[counter];

}

cout << endl;
cout << endl;


for (int counter = 1; counter <= size; counter++)

{
    cout << "Element " << counter << " is " << array[counter] << "." << endl;
    cout << endl;

}

cout << "*bing! :)" << endl;
cout << endl;


return 0;
}

【问题讨论】:

    标签: c++ arrays buffer-overflow


    【解决方案1】:

    这是未定义的行为。 UB 有多种口味。以下是一些:

    1) 它会踢你的狗。

    2) 它将重新格式化您的硬盘。

    3) 它将毫无问题地工作。

    在您的情况下,使用您的编译器和在您的平台上,在这一天,您会看到 (3)。但是在其他地方尝试一下,您可能会得到 (1)、(2) 或其他完全不同的结果(很可能是访问冲突)。

    【讨论】:

    • 它也可能导致矩阵出现故障。
    【解决方案2】:

    C/C++ 在使用数组时不做边界检查。

    因为您要声明一个基于堆栈的数组。访问数组边界之外只会访问已分配堆栈空间的另一部分。

    所以基本上当您访问超出范围的内容时,它不会引发分段错误,除非它完全超出您的堆栈内存。

    C/C++ 对数组边界很危险,记住这一点!

    【讨论】:

    • 我对带有动态大小变量的堆栈的内存布局有点好奇。在我的笔记本电脑上 (i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)) gdb 的“print (char*)&size - (char*)&array[size] " 表示 84 或 96(取决于我输入的大小)。我不确定他们之间是什么。 valgrind 甚至没有发现错误。我反汇编了函数,但组装比我希望的要复杂。
    【解决方案3】:

    堆栈非常大。在 Windows 上,it's 1 MB

    由于程序没有做太多事情,所以数组会被分配到接近堆栈的开头。这意味着在数组末尾和堆栈末尾之间将有将近 1 MB 的空白空间。

    那么这是什么意思?当你写到数组的末尾时,你只是在破坏你自己的堆栈空间,而不是其他程序,所以操作系统不会阻止你,程序会继续运行。

    【讨论】:

    • 堆栈向下增长,因此空白部分不在数组的开头,而不是结尾。否则正确。
    • 是的,在VS2013中,我曾经声明了一个数组int a[65535],直到a[i]i == 84330,程序抛出异常。
    【解决方案4】:

    这里,你知道数组索引从0开始到5

    您输入的计数器为 5,从 1 开始并转到 5

    您将索引 1 用于计数器 1,索引 2 用于计数器 2,依此类推。

    索引 0 仍然没有输入值并且包含垃圾值。

    【讨论】:

      【解决方案5】:

      首先,数组大小需要保持不变

       int arr[size] 
      

      由于 size 是一个变量,因此不起作用,因此,要么在编译时固定数组的大小,要么使用动态内存分配。

      即 要么

        const int size =5; 
        int arr[size];
      

        int arr[5];
      

        int* arr = new int[5];
      

      和..

      保证将指针指向数组末尾之外的一个元素在 C++ 中可以正常工作。这对于 STL 提供的许多算法很重要。但是,由于这样的指针实际上并不指向数组的元素,因此它可能不用于读取和写入。另一方面,在初始元素之前获取元素地址的结果是未定义的,应该避免..

      即你可以取那个变量的地址然后回来但是不能用!!!

      【讨论】:

      • 什么?不保证在数组之外获取元素(分段错误)。此外 Size 是 int 类型,也就是说 int size = 5; int arr[5]。这个答案是非常错误的。
      • 可变长度数组是 C 的一个特性,它在许多 C++ 编译器中作为扩展实现。 int arr[size]; 是有效的 C99。
      • @Kevn,您可以获取数组末尾之外的元素地址,但不能取消引用该地址 (stackoverflow.com/questions/1021021/…)。然而,与这个问题并不真正相关。
      • 这就是我的意思,您可以将指针移动到数组之外的一个元素,但不能读取或写入它!大小需要是一个常数意味着 const int size =5; int arr[大小];或 int arr[5];
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-20
      相关资源
      最近更新 更多