深入讲解函数中分配内存问题

西门子smart能搜到cpu但连接当前IP地址失败 将ip地址改到同一网段 本机为192.168.1.119就是192.168.1.1网段,但plc在192.168.0.1网段,所以显示ip连接失败,改为同一网段192.168.1.xxx即可(为避免ip冲突尽量改到200往后最大255)如果显示这一步,那么你的物理连接是没有问题的,应当是plc和电脑并不在同一网段导致的问题。输入ipconfig 查看本机网段与plc是否为同一网段。此电脑就不在同一网段所有造成通讯失败,接下来解决这个问题。win+r打开运行,打开cmd。再次尝试,如果还是报错,那么。 阅读详情

原文地址:http://www.cppblog.com/Leaf/archive/2010/05/05/114425.aspx

声明:这随笔是无聊或是一时兴起写的。 没有其它什么目的。愿意看的就看。如果只是想用用C/C++不出错。能跑跑程序就行。那大可不必这么累地看下去。本博客中还有一个“基于C++规则”来解释这个东西的随笔。

我只想说,萝卜青菜,各有所爱!
我也不是一个死抠语言的爱好者。
甚至我是基本无视语言的。


写这个,纯属娱乐。。
谢谢各位捧场!!! 

好了,有闲功夫的朋友们,或者说想了解“规则”之下的东西的朋友们。请继续往下看!

先看这样的代码

 1 void  MyNew( int   * p)
 2 {
 3    p = new int;
 4}

 5
 6 int  main()
 7 {
 8    int *p = NULL;
 9    MyNew(p);
10}


开始写了一篇:函数中分配内存的问题(点击进入),通过说明他们产生了拷贝,而导致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, 的确,它是放了,但是,这个p其实不是main中的那个p了。所以,最后,main函数中,p所指向的地址并没有改变。



void  MyNew( int   *& p)
{
    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}的方式,其实这个传递引用是完全等效的。甚至,反汇编后,他们是同样的代码。


终于写完了。有很多地方觉得还是没讲清楚,希望各位大大指教,小弟立马修改。 洗过头,上班去!!

第一章:基础知识 - 概念与基础,理解什么是功耗 电源管理与功耗调优:实战项目经验分享 阅读详情

相关推荐

Unity获取透明物体深度数据

Unity获取透明物体深度数据前言透明&景深需求模型透明度部分带透明通道图片/视频部分半透明模型获取深度的具体实现方法带透明度图片/视频获取深度的具体实现方法结束语 前言 最近在做的项目有很多奇怪的需求,甚至之前在unity里用插件写了一个类似于蓝图的行为树插件,之后有时间给大家讲一讲相关的实现方法,今天刚解决了unity里透明物体无法获得深度数据的问题。所以分享给大家。 透明&景...

可以吃的妙脆角的博客 2631

深入理解函数中分配内存的问题

深入理解函数中分配内存的问题 先看这样的代码 1voidMyNew(int*p)2{3p=newint;4}56intmain()7{8int*p=NULL;9MyNew(p);10} 开始写了一篇函数中分配内存的问题,通过说明他们产生了拷贝,而导致p不能成功分配。但并未提出事实根据,...

15 年专注游戏引擎与游戏开发,分享实用方案、经验与干货教程! 4377

更多 LSTM 变种——应用于 CMAPSS 数据集

本文并模型介绍,只是把一些比较火的技术,像双向注意力机制,自注意力机制这样的比较火的内容,简单的和LSTM堆叠,结果发现效果都不如最基础的,这里作者将本人代码及实现结果,进行展示,给各位想更改LSTM的朋友一些。

2301_77491330的博客 1765

对某APP的逆向之旅(3)

书接上回,本次对前面解密后的so进行分析 来到start函数 进入主函数 sub_9960首先创建本地socket,用于通信,然后while循环中,不断读取java层的消息,执行对应的功能函数。 创建socket的代码如下:void __fastcall sub_9960(int a1, void **a2) { ...... ...... port = atoi(&s); v6

csky的博客 801

数字IC面试核心:从MUX基础到Glitch-Free时钟切换电路深度剖析

本文深入剖析数字IC设计中的MUX基础原理及其在Glitch-Free时钟切换电路中的应用。从二选一MUX的门级实现到时钟切换中的毛刺问题,详细讲解了同步切换机制和工程优化技巧,帮助工程师掌握高速时钟电路设计的核心要点。

weixin_42629815的博客 324

Kafka 系列 —(17)Kafka 流式处理:Kafka Streams架构、使用场景、框架选择

本文介绍了KafkaStreams的架构特点、应用场景及与其他流处理框架的比较。KafkaStreams作为嵌入式分布式流处理库,其核心架构包含流处理器、任务、拓扑和本地状态存储,具备自动容错和伸缩能力。适用于实时监控、ETL、聚合、Join、物化视图等低延迟场景。与Flink、Spark相比,KafkaStreams适合简单架构和微服务,而Flink适合大规模处理,Spark更适合批处理。选择框架需根据具体场景需求,如微服务推荐KafkaStreams,大规模处理推荐Flink。

moton2017的博客 1631

函数中的内存动态分配

动态分配使用不当会造成内存泄漏,这里分享一个最容易被忽略的内存泄漏现象。 #include <iostream> char * func(void); int main(){ char *pm = NULL; pm = func(); /* ** Do something */ return 0; } char * func(...

pix_csdn的博客 1025

引入 CloudWeGo 后飞书管理后台平台化改造的演进史

飞书管理后台是飞书套件专为企业管理员提供的信息管理平台,它通过引入 Kitex 泛化调用对飞书管理后台进行平台化改造,成为了企业统一数字化管理平台。本文将从三个方面为大家讲解 Kitex 泛化调用在飞书管理后台平台化改造过程中的落地实践。...

weixin_44186218的博客 1762

C/C++ 笔试面试(3)——内存管理GetMemory

1.关于动态申请内存的问题 出现率极高 程序的局部变量存在于(栈)中 程序的全局变量存在于(静态存储区)中 程序动态申请的数据存在于(堆)中 void GetMemory(char *p) { p = (char *)malloc(100); } void Test1(void) { char *str = NULL; GetMemor

小熊不去实验室 1万+

Claude Code 100个真实案例 - 用AI设计Arduino PCB电路板(硬件小白也能画板)

本案例展示如何使用 Claude Code 配合 KiCad 的 Python 脚本接口,从零设计一块 Arduino 传感器扩展板 PCB。从原理图符号创建、网表生成到 PCB 布局布线,全程自动化完成,最终输出可直接发给工厂打样的 Gerber 文件。

yueyeguzhuo的专栏 438

Python 爬虫实战:爬取 BOSS 直聘职位,实现岗位要求关键词提取

摘要:本文基于BOSS直聘数据分析师岗位信息,采用Python爬虫技术获取职位数据,通过文本分析和可视化方法研究岗位技能需求特征。研究首先设计爬虫程序获取职位基本信息和岗位要求文本,经数据清洗后运用jieba分词和词频统计提取关键词。结果显示SQL、Python为最核心技能,不同级别岗位需求差异明显:初级重基础数据处理,高级需建模和管理能力;行业间亦存在差异,互联网关注用户增长,金融侧重风控。研究为求职者技能提升提供了数据支持,同时展示了从非结构化文本中挖掘有价值信息的完整流程。

2503_91057718的博客 1765

函数参数的传递问题(指针的指针)

程序1: void myMalloc(char *s) //我想在函数中分配内存,再返回 {   s=(char *) malloc(100); } void main() {   char *p=NULL;   myMalloc(p); //这里的p实际还是NULL,p的值没有改变,为什么?   if(p) free(p); } 程序2: void myMalloc(ch

GOON 743

小程序跳转链接实战:https://wxaurl.cn/、weixin://dl/business/ 跳转与明文 URL Scheme 生成指南

本文聚焦小程序跳转链接开发核心技术,深入解析 https://wxaurl.cn/*TICKET* 与 weixin://dl/business/?t= *TICKET* 两种链接的生成方法。详细阐述生成前的准备工作、服务端接口调用步骤及注意事项,同时剖析 iOS 与 Android 系统在链接适配方面的差异。此外,针对明文 URL Scheme 获取,从平台设置、拼接规则、使用限制等方面展开讲解,并结合实际应用案例提出优化建议,帮助开发者快速掌握小程序跳转链接生成与明文URL Scheme获取的关键技术。

邓邓子的博客 2万+

如何自实现一个malloc函数(指定区间分配)

如何实现一个malloc函数一、概述1、malloc简介函数所在头文件:&lt;stdlib.h&gt;函数原型是:void *malloc (size_t n)函数功能:在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。 2、malloc函数使用注意事项申请了内存空间后,必须检查是否分配成功。当不需要再使用申请的内...

奋斗在路上的博客 5124

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

C语言函数如何返回数组

我们先来看一下,根据直观直觉写出来的错误代码是怎么样的return a;错误结果`t此处表示,返回了一个局部变量的地址,也就是说,返回局部变量的地址是非法的。这里的知识与数据结构“栈”有关,我们可以暂时理解成如下语言:当函数返回一个值的时候,可以把这个值传递到外界,那么函数返回数组时,相当于返回一个地址。此时,地址和值是等价的,函数一样把地址传到了外界。但是函数的生命周期在return完之后就已经结束了,因此内存被释放。

2402_88630322的博客 521

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

C语言复习(函数)

C语言函数部分复习,以后忘记了回头来看看

qq_57511928的博客 306

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

c语言函数返回指针指针,深入理解C语言中的指向函数的指针和返回指针的函数!...

#include#include/** 返回指针的函数和指向函数的指针*//** 定义一个函数,返回一个void指针,在C语言中,void指针可以* 指向任何类型*/void *func(){/** 一种很容易犯的错误,将局部变量的地址返回*/int m;printf("define as void *func()/n");return &m;}/** 声明一个指向函数的指针,指向返回类型...

weixin_33940733的博客 722

❥关于C++之定位new运算符•显示调用析构函数

程序员必须负责管用定位new运算符用从中使用的缓冲区内存单元。要使用不同的内存单元,程序员需要提供两个位于缓冲区的不同地址,并确保这两个内存单元不重叠。例如,可以这样做: char* buffer = new char[512]; JustTesting* pc1 = new (buffer) JustTesting;// place object in buffer JustTesting* pc2 = new (buffer + sizeof (JustTesting)) JustTesting("

itzyjr的专栏 1320

c++学习笔记 类和动态内存分配与特殊成员函数

上一个例子中是仿string类Str使用的是char数组类储存,但是这样有大小限制(100),能不能让它动态的进行调整大小呢? 已定义的char数组行不通,但是让一个指针指向一块规定大小的内存是可以的,于是我可以使用内存分配来完成任意大小的Str类 这种方法叫动态内存分配:

nonororo的博客 764

一步一步写算法(关于malloc函数)

一步一步写算法(关于malloc函数)

Clearfix_Xia 404

【C语言指针进阶讲解】第七章:实践与项目

内存池 (Memory Pool) 是一种内存管理技术,可以显著提高程序的性能,减少内存碎片。内存池通过预先分配一大块内存,然后根据需求动态分配固定大小的小块内存。A1: 内存池的主要目的是提高内存分配的效率和减少碎片。A3: 函数指针广泛用于回调机制、事件驱动编程、插件系统等场景,能实现灵活的代码调度和模块化设计。以上示例展示了如何逐步实现一个简单的内存池,并通过代码注释和输出验证其功能。A2: 可以通过调整内存池大小或增量扩展多个内存池来处理内存不足的情况。

621

c++中传递字符指针容易犯的错误

先看一段容易犯错的代码段: #include using namespace std; char* GetMe() { char st[]="hello word!"; return st; } int main() { char *str; str=GetMe(); cout<<str<<endl; return 0; } 该段代码可能输出正确结果,也可能输出错误结果。原

小博客 3400

c++学习笔记——类和动态内存分配

在类中使用动态内存分配的原因:避免占用太多内存空间,在程序运行时(而不是在编译时)确定要使用多少内存,最常用的方法就是在类构造函数中使用new运算符在程序运行时分配所需的内存。

m0_68388605的博客 579

c语言十七:动态内存申请

动态内存申请一 动态内存申请二 静态分配内存和动态分配内存2.1 静态分配内存2.2 动态分配内存三 动态内存申请的相关函数3.1 分配内存空间函数 malloc3.2 free函数 (释放内存函数)3.3 案例一:从堆区申请一个int类型的空间3.4 案例二:从堆区申请一个数组,数组的大小由用户决定3.5 calloc函数3.5 realloc函数(重新申请内存空间)四 内存泄漏 一 动态内存申请 数组的长度是预先定义好的,在整个程序中固定不变; 但在实际应用中,往往有这种情况,所需要的内存空间取决

qq_33808440的博客 6814

64 源码_内存管理(Linux内核源码分析)

背景本篇博客试图通过linux内核源码分析linux的内存管理机制,并且对比内核提供的几个分配内存的接口函数。然后聊下slab层的用法以及接口函数。内核分配内存与用户态分配内存内核分配内存与用户态分配内存显然是不同的,内核不可以像用户态那样奢侈的使用内存,内核使用内存一定是谨小慎微的。并且,在用户态如果出现内存溢出因为有内存保护机制,可能只是一个报错或警告,而在内核态若出现内存溢出后果就会严重的多...

weixin_29215815的博客 235
上一篇: Doxygen注释风格
下一篇: Vector容器的一点说明
henrik_he
博客等级 码龄16年 36粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值