深入讲解函数中分配内存问题
来源:互联网 发布:c语言 goto坏处 编辑:程序博客网 时间:2024/06/05 00:20
声明:这随笔是无聊或是一时兴起写的。 没有其它什么目的。愿意看的就看。如果只是想用用C/C++不出错。能跑跑程序就行。那大可不必这么累地看下去。本博客中还有一个“基于C++规则”来解释这个东西的随笔。
我只想说,萝卜青菜,各有所爱!
我也不是一个死抠语言的爱好者。
甚至我是基本无视语言的。
写这个,纯属娱乐。。
谢谢各位捧场!!!
好了,有闲功夫的朋友们,或者说想了解“规则”之下的东西的朋友们。请继续往下看!
先看这样的代码
2{
3 p = new int;
4}
5
6int main()
7{
8 int *p = NULL;
9 MyNew(p);
10}
而放入的那个p, 的确,它是放了,但是,这个p其实不是main中的那个p了。所以,最后,main函数中,p所指向的地址并没有改变。
开始写了一篇:函数中分配内存的问题(点击进入),通过说明他们产生了拷贝,而导致p不能成功分配。但并未提出事实根据,下面我们来仔细看看具体原因。
我们需要弄清两点:1、main函数中的p与MyNew函数中的p是不是一样;2、如果不一样,是怎么导致了不一样的。
第一点很好看,我们可以在编译器(VC环境,我用的是VS 2005)的监视窗口中跟踪p的地址。
在监视窗口中增加一个对 &p的监视,然后我们在int*p = NULL处添加一个断点。单步执行,停在MyNew函数前,此时我们可以看到,&p的值为 0x0012ff60 . 然后,我们单步进入MyNew函数,此时我们可以发现,&p的值变成了0x0012fe8c 明显,它们不是同一个东西,这样在MyNew操作的时候,操作的就不是我们想要操作的那个p(0x0012ff60). 好了,不要去猜测这两个数字之间的关系,接下来会给你一个满意的答案.
先看看下面这个反汇编的结果
int *p = NULL;
0041153E mov dword ptr [p],0
MyNew(p);
00411545 mov eax,dword ptr [p]
00411548 push eax
00411549 call MyNew (41116Dh)
红色部分就是将p作为参数压栈,然后call MyNew,注意,此时我们的p已经被保存起来了。
void MyNew(int *p)
{
004114C0 push ebp
004114C1 mov ebp,esp
004114C3 sub esp,0CCh //红色:分配33*4Bytes 临时空间
004114C9 push ebx
004114CA push esi
004114CB push edi
004114CC lea edi,[ebp-0CCh]
004114D2 mov ecx,33h
004114D7 mov eax,0CCCCCCCCh
004114DC rep stos dword ptr es:[edi] //蓝色:初始化分配的空间为 0xcccccccc
p = new int;
004114DE push 4
004114E0 call operator new (411190h) //调用new 返回值存放于eax中。
004114E5 add esp,4
004114E8 mov dword ptr [ebp-0C8h],eax //将new出来的地址放到ebp-0c8h中
004114EE mov eax,dword ptr [ebp-0C8h] //将new出来的值放到eax中,作为返回值。
004114F4 mov dword ptr [p],eax //将eax中的值放入p中
}
//下面是清栈操作
004114F7 pop edi
004114F8 pop esi
004114F9 pop ebx
004114FA add esp,0CCh //清除临时变量
00411500 cmp ebp,esp
00411502 call @ILT+325(__RTC_CheckEsp) (41114Ah)
00411507 mov esp,ebp
00411509 pop ebp
0041150A ret
上面的东西不能说明根本问题,因为没有作任何分析,下面我们就来仔细分析一下,特别是最后的 004114F4 mov dword ptr [p],eax 有人就会问,既然已经放回了p中,为啥p还是没变呢。
这就是new之间的堆栈空间示意图,可以看出,我们传入的参数是ebp+8,而当new回来后,却用的是004114E8 mov dword ptr [ebp-0C8h],eax 很明显,ebp-0c8 是临时分配的空间。
{
p = new int;
}
我们将代码稍作修改,改成传递指针的引用,那又会发生什么呢。首先,我们按照上面的方法检测其地址。 你会发现,两个函数中的地址都是 0x0012ff60.
那,为什么会这样呢,我们看看两个地方,第一就是参数传递时的压栈。
00411535 lea eax,[p]
00411538 push eax
00411539 call MyNew (4111F4h)
可以看出,这次传递的,并非是像开始一样 mov eax, dword ptr[p] 。二者的差别在于,上一次(没有采用引用传递)传递的是值,而这一次(采用了引用传递)传递的是指针p的地址。
接下来,我们再来看看刚刚new出来之后赋值的地方。
004114E8 mov dword ptr [ebp-0C8h],eax
004114EE mov eax,dword ptr [p]
004114F1 mov ecx,dword ptr [ebp-0C8h]
004114F7 mov dword ptr [eax],ecx
可以发现,这正是我们传中说的:取得p的地址,采用*p求出p所指向的地址。然后对*p赋值,以改变它的值。。
还有一种就是指针的指针void MyNew(int** p){*p = new int}的方式,其实这个传递引用是完全等效的。甚至,反汇编后,他们是同样的代码。
终于写完了。有很多地方觉得还是没讲清楚,希望各位大大指教,小弟立马修改。 洗过头,上班去!!
http://www.cppblog.com/Leaf/archive/2010/05/05/114425.aspx
- 深入讲解函数中分配内存问题
- 深入讲解函数中分配内存问题
- 深入理解函数中分配内存的问题
- 函数中分配内存的问题
- 函数中分配内存的问题-zz
- 函数中分配内存的问题
- 函数中分配内存的问题
- DLL函数中内存分配及释放的问题
- C++中内存分配、函数调用和返回值问题
- C++中内存分配、函数调用和返回值问题
- C++中内存分配、函数调用和返回值问题
- C++中内存分配、函数调用和返回值问题
- C++中内存分配、函数调用和返回值问题
- 关于函数中栈内存的分配问题追踪
- c中存储类型,以及调用内存分配函数----细致讲解
- java中内存分配深入分析
- 动态内存分配讲解
- 内存分配深入探讨
- 不宜创建索引的情形
- error: argument of type 'void* (My_Thread::)(void*)' does not match 'void *(*)(void*)'
- Cache
- 数字图像处理编成入门笔记——第6章腐蚀,膨胀,细化算法
- c++线程调用函数必须为static
- 深入讲解函数中分配内存问题
- 《网站做的好与坏要用户说了算》之计划变更原则
- 回调函数
- 强制换行
- 是谁妖魔化了QA
- 学习jsf过程中遇到页面将el表达式当做字符串的解决办法。
- C#访问BitMap几种方法效率比较
- 转载Oracle 客户端软件 8.1.7 或更高版本。
- 转载Oracle 客户端软件 8.1.7 或更高版本。