5

好的,所以我正在教我的女朋友一些 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;
}
4

5 回答 5

22

这是未定义的行为。UB 有多种口味。这里有几个:

1)它会踢你的狗。

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

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

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

于 2012-04-07T04:39:24.707 回答
6

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

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

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

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

于 2012-04-07T04:40:52.860 回答
2

堆栈非常大。在 Windows 上,它是 1 MB

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

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

于 2012-04-07T05:11:24.877 回答
0

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

 int arr[size] 

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

即要么

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

或者

  int arr[5];

或者

  int* arr = new int[5];

和..

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

即,您可以获取该变量的地址,然后返回但不能使用它!!!

于 2012-04-07T04:46:27.677 回答
0

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

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

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

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

于 2012-04-07T04:51:14.827 回答