这是我在这个论坛上的第一个问题,抱歉我的英语不好。 我对c ++中的指针和动态内存有疑问。
示例,此代码:
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
int *a = new int;
for (int i = 0; i < 5; i++)
cout << a++ << endl;
return 0;
}
输出:
0x11d4c20
0x11d4c24
0x11d4c28
0x11d4c2c
0x11d4c30
我的问题是,为什么我可以移动的内容超过我使用new
创建的“单个”内存块。
a
指向的是什么? new int[]
也是如此,即使我具体说明了这个尺寸:
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
int *a = new int[2];
for (int i = 0; i < 5; i++)
cout << a++ << endl;
return 0;
}
输出:
0x2518c20
0x2518c24
0x2518c28
0x2518c2c
0x2518c30
再一次,发生了什么?
a
指向什么?这一切是否意味着我在侵犯记忆?
答案 0 :(得分:1)
a
是int*
,而不是int
。您正在打印的内容实际上是指针,即指向对象的内存地址。只要你想修改指向值,即
*
cout << (*a)++ << endl;
注意:同样,您可以使用引用运算符&
获取指向int的 指针,而不是与引用(例如int&
类型混淆)。
此可能打印0 1 2 3 4
。 可能因为您没有初始化在动态内存中创建的新int
。这意味着从*a
(取消引用a)读取未定义的行为,这意味着您的程序可能行为不当。您必须使用new
更改自己的行:
int *a = new int();
这会将*a
初始化为0
,现在0 1 2 3 4
将正确打印。
请注意,int *a = new int[2];
确实在动态内存中创建了2个条目的动态数组,这意味着*(a + 1)
也可以使用(就像它是常规数组一样)。 不将*a
初始化为2。
在使用完毕后,请记得delete a;
。在实际应用程序中,如果不这样做,可能会出现内存泄漏 - 即您的程序仍然会使用它不再需要的内存。注意,当你必须删除一个动态分配的数组(即new int [2])时,你需要使用delete[] a;
,否则你将触发未定义的行为。
您也可以在C ++ 11中使用unique_ptr
(或shared_ptr
)作为此类内存分配的替代方法,即:
#include <memory>
// ...
std::unique_ptr<int> a = std::make_unique<int>(0);
感谢此解决方案,您不需要delete a
,因为unique_ptr
会在您自己死亡时(即在此范围之外)为您执行此操作。
编辑:奖金:
0x2518c20
0x2518c24
0x2518c28
如果您刚使用++
?
在地址上使用++
实际上会将其增加sizeof(T)
,此处为sizeof(int)
而非1
。这解释了为什么如前所述,如果您使用*(a + 1)
,则可以使用new int[2]
。
答案 1 :(得分:0)
我认为它是,因为指向一个整数,一个整数的大小是4个字节(sizeof(int)== 4)在执行++之后,a指向下一个整数,尝试char * a,并且a ++更加确定
答案 2 :(得分:0)
指向对象之后的对象或点是合法的。 new int[2]
创建两个相邻的对象(在数组中)并返回指向第一个对象的指针。
所以是的,你上面所做的是不允许的。向单个对象的指针添加5的行为不是由C ++标准定义的。编译器可以生成任何可以执行任何操作的程序集。
实际上,在平面内存架构上,指针基本上是无符号整数。将指针递增1只是按指向对象的大小递增它。
所以经常发生的事情就是你只是指向那里发生的事情。
现在这不保证,不应该依赖。许多使操作未定义的C ++规则允许在您可能认为编译器执行的“天真”映射上进行某些优化。例如,指向short
的指针永远不会指向int
并以定义的方式更改其值,这意味着如果函数同时具有int
和short
指针可以假设对short
的写入不会修改int
。
天真的“写入int中的两个单词”使用short的方法可以工作,然后看似没有理由不起作用,因为行为是未定义的并且编译器可以自由地优化假设它不会发生
简而言之,你的行为不合法,你所获得的行为并不令人惊讶,但你永远不能依赖它。
指针不仅仅是无符号整数,即使这是编译器实现它们的原因。它们是一种抽象。他们的行为不是由他们的实施决定的,而是由标准允许你做的。当您以标准不允许的方式行事时,您获得的行为未被标准定义。编译器可以并且已经知道利用该事实来假设未定义的行为不会也不会发生。在未定义行为之前,程序可能会在代码行上意外地行为,因为编译器会根据您的代码具有良好定义行为的假设重新排序和优化。
答案 3 :(得分:-1)
c ++(和c)中的指针只是内存的地址(32/64位数)。增加它们或减少任何你想要的方式没有问题,你没有违反内存或任何其他规则。但是,如果您在经过A
周期后尝试读取或写入for
指向的地址,则会侵犯内存。
至于它指向的是什么,很可能它只是由new
(以及它下面的malloc
分配给你的更多空间,因为它往往会提供比你要求更多的空间,虽然这种行为无法保证。它也可能指向堆数据或只是未分配的内存。