这已经困扰了我好一段时间了。我有一个指针。我声明了一个类型为int的数组。
int* data;
data = new int[5];
我相信这会创建一个大小为5的int数组。因此,我将能够从data [0]到data [4]存储值。
现在我以相同的方式创建数组,但是没有大小。
int* data;
data = new int;
我仍然能够将值存储在data [2]或data [3]中。但是我创建了一个大小为1的数组。这怎么可能?
我知道数据是一个指向数组第一个元素的指针。尽管我没有为下一个元素分配内存,但是我仍然可以访问它们。怎么样?
谢谢。
new int
仅分配1个整数。如果您访问的偏移量大于0,例如data[1]
您覆盖内存。
超出C ++中数组的边界是未定义的行为,因此任何事情都可能发生,包括看起来“正确”地工作。
在常见系统的实际实现术语中,您可以将“虚拟”内存视为从0到指针大小的大“平坦”空间,并且指针进入该空间。
进程的“虚拟”内存已映射到物理内存,页面文件等。现在,如果您访问未映射的地址,或尝试编写只读部分,则会收到错误消息,例如作为访问冲突或段错误。
但是此映射是针对相当大的块进行的,以提高效率,例如4KiB“页面”。进程中的分配器,例如new
和delete
(或堆栈),将根据需要进一步拆分这些页面。因此访问有效页面的其他部分不太可能引发错误。
这具有不幸的结果,可能难以检测到这种超出范围的访问,在释放之后使用等。在许多情况下,写操作将成功,只会破坏其他一些看似无关的对象,这可能会在以后导致崩溃;或者错误的程序输出,因此最好对C和C ++内存管理非常小心。
data = new int; // will be some virtual address
data[1000] = 5; // possibly the start of a 4K page potentially allowing a great deal beyond it
other_int = new int[5];
other_int[10] = 10;
data[10000] = 42; // with further pages beyond, so you can really make a mess of your programs memory
other_int[10] == 42; // perfectly possible to overwrite other things in unexpected ways
C ++提供了许多工具来帮助,例如std::string
,std::vector
和std::unique_ptr
,通常最好完全避免使用手册new
和delete
。
通常,不需要分配带有new
的数组。改为使用std::vector<int>
更方便,也更安全。
[std::vector<int>
可选地通过at()
方法为元素访问提供边界检查。
示例:
#include <vector>
int main() {
std::vector<int> data(5);
data[3] = 10; // element access without bounds checking
data.at(10) = 0; // invalid element access triggers a runtime exception
}
C ++中的默认模式通常是允许您以未定义的行为射击自己的脚。
供参考: