浅谈指针(二级指针动态分配内存)
- 指针
指针的本质是地址 - 指针变量
指针变量是一个能存储地址的变量
定义:
DataType *变量名;
其中( DataType * ) 是地址类型(地址是有类型的!)(例如定义一个 int 型变量 a,变量 a 的地址 &a 类型为 (int *)型)
double *p = NULL;
其意义可解释为:定义了一个指针变量p,并为 p 分配4个字节的存储单元(32位机中地址统一占4个字节), 能存储一个 double 型变量的地址。(这里已经为指针 p 初始化指向NULL)
sizeof(p);
输出结果为 4 ; 可见(地址)指针变量 p 占4个字节
再说一下指针(地址)的指向
指针(地址)的指向就是单元(这块存储空间内存储的值)。
‘ * ’ 为指向运算符
int *p = NULL;
int m = 10;
p = &m;
补充一点知识:
通常我们所说的地址都是变量所占内存空间中第一个字节的地址!
例如:
int a = 10;
printf("&a : %x \n &a +1 : %x \n",&a,&a+1);
输出结果 :
&a : 6dfef8
&a +1 : 6dfefc
在这段简单代码中声明了一个int 型变量a,同时为 a 分配4个字节的存储空间,从输出结果可以知道每个字节都占有一个地址编号,而 变量 a占用的4个字节的地址编号是从 6dfef8~~ 6dfefb
&a +1 是对地址进行加减运算,地址的加减运算规则如下: 地址 +/- n <==> 地址 +/- n*sizeof(地址类型)。 上例中的
&a + 1 <==> &a + 1*sizeof(int) 即 6dfef8 + 1*4 = 6dfefc
现在可以简单的理解地址与地址的指向的关系,那么问题来了,我们知道我们能看的的变量单元的地址仅仅是该变量所占内存空间第一个字节的地址,很显然只知道一个字节的地址是无法访问到全部内存单元的,那计算机又是如何知道该单元占用的总字节数呢?如何通过地址访问变量单元呢?
- 指针类型
我们知道定义变量的时候一定会确定其数据类型(int double float char…),这是一个很关键的点,有了第一个字节的地址,有了地址类型,计算机就可成功访问到一个变量单元。
所以想要成功访问一个变量单元,一定是 变量第一个字节的地址 + 地址类型
也就是指针类型。
所以在程序中若出现指针类型不匹配的情况下会报错
例如
int a = 10;
char * p = NULL;
p = &a;
解决方案:强制类型转换
p = (char *)&a;
- 指针做函数返回值
qiao hei ban!!!其实下面才是我要说的重头戏。
在一个函数执行完毕后其所占用的内存空间(除 了静态和全局变量)统统会被释放掉,对于有返回值的函数一般都是返回一个值,其本质就是将返回的变量单元中的值的副本返回主调函数中;
如果返回值是一个地址呢?还会正常返回吗?
先来一段代码
int *b()
{int a = 10;cout << &a;return &a;
}
int main()
{if(b() == NULL){return -112233;}return 0;
}
程序运行结果:
第一个输出是在函数b()中正常输出局部变量a 的地址,函数运行结束后 a所占的内存空间被 释放 ,同时带回“&a”,在main()中对返回的"&a"进行了一个检测,根据返回 -112233发现 返回的"&a’ 并不是上面输出的0x6dfeec而是一个空地址!
再看下面一段代码
int *a()
{static int a = 10;cout << &a << endl;return &a;
}
int main()
{int *p = NULL;p = a();cout << p << endl << *p;return 0;
}
输出结果
这次只是将变量a 由局部变量变为了静态变量 (局部变量分配在内存的栈区域,静态和全局变量分配在内存堆区域),不仅可以成功返回其地址,且正确通过指针 P 输出了 a 的值。
小结:
函数返回值是指针(地址)时,要注意其变量类型,如果是局部变量,则无法成功返回地址。
静态变量和全局变量则可以成功返回;
原因:函数运行结束释放其所占的所有栈空间
- 利用二级指针动态分配内存
先来一段代码
struct Teacher
{char name[81];int age;
};
int getTeacher(Teacher **p)
{Teacher *tmp = NULL;if(p == NULL){return -1;}tmp = (Teacher *)malloc(sizeof(Teacher));if(tmp == NULL){return -2;}tmp->age = 33;*p = tmp;
}
int main()
{Teacher *pT1 = NULL;getTeacher(&pT1);if(pT1 == NULL){return -1122233;}cout << "age:" << pT1->age << endl;return 0;
}
运行结果
这段代码通过函数用二级指针为 pT1 分配内存并填入age 的值,算是对上一个小标题的补充实战,为什么不能在函数内用一级指针分配内存呢?
malloc()函数分配的内存在堆上,如果不被程序员手动free(),在程序结束之前该段内存空间始终存在。
如果将getTeacher()中的形参变为一级指针会是什么效果
int getTeacher(Teacher *p)
{Teacher *tmp = NULL;if(p == NULL){return -1;}tmp = (Teacher *)malloc(sizeof(Teacher));if(tmp == NULL){return -2;}tmp->age = 33;p = tmp;
}
如果继续在主调中调用此函数
int main()
{Teacher *pT1 = NULL;getTeacher(pT1);if(pT1 == NULL){return -1122233;}cout << "age:" << pT1->age << endl;return 0;
}
运行结果
会发现pT1是一个空指针,也就是通过函数并没有为pT1分配内存空间。
用图分析一下指针指向变化
1.二级指针做形参
第一步: getTeacher(&pT1); 执行 p = &pT1;让二级指针 p 指向 一级指针 pT1;
第二步:malloc()函数分配内存
第三步:一级指针 tmp 指向刚才malloc()分配的内存空间
第四步:*p = tmp;由于 *p = pT1; 故 实际执行语句 pT1 = tmp
( 此时pT1已经指向malloc()分配的内存)
第五步:函数执行完毕,释放二级指针 p 和一级指针 tmp ,malloc()分配的内存空间由于在堆区而被保留了下来
此时pT1已经指向malloc()分配的内存。使用函数用二级指针间接分配内存成功。
再来图解一下一级指针做函数形参为什么不能间接动态分配内存
2.一级指针做函数形参
第一步: getTeacher(pT1); 执行 p = pT1;让一级指针 p 指向 一级指针 pT1;
第二步:malloc()函数分配内存
第三步:一级指针 tmp 指向刚才malloc()分配的内存空间
第四步:p = tmp; 此时p 的指向关系被改变,由原来的指向 pT1 变为指向 tmp;
( 此时pT1仍然指向NULL)
第五步:函数执行完毕,释放二级指针 p 和一级指针 tmp ,malloc()分配的内存空间由于在堆区而被保留了下来
此时看图就可以明白一切了,话不多说,很明显pT1和分配的那块内存空间并没有指向关系。
世界与我同在,代码能力可期。在这个0/1世界里,努力升级打怪才是王道。期待总有大佬来踢馆~~
浅谈指针(二级指针动态分配内存)相关推荐
- C 结构体嵌套一级指针 二级指针 动态分配内存
https://blog.csdn.net/xielinhua88/article/details/51364623 点击打开链接 #define _CRT_SECURE_NO_WARNINGS #i ...
- 浅谈下二级域名做网站优化的利与弊!
不要说认不清二级域名与一级域名,好吧我在重复再重复的解释下 zibk.cn 这种是属于一级域名 也叫做主域,而 www.zibk.cn 这种则为二级域名,一级域名只能解析一个,二级域名则可以无穷个,在 ...
- 浅谈C++跨模块释放内存
浅谈C++跨模块释放内存 一, MT改MD 二, DLL提供释放接口 三, 使用进程堆申请内存 在开发主程序和动态库时,首要原则就是:避免跨模块申请和释放内存.这一点,我们在很多开源库或者平常项目中也 ...
- 【指针】一级指针二级指针知识点梳理
目录 一.普通指针(一级) 1.定义 2.指针变量和普通变量的异同点 3.使用: 4.指针字节大小 5.习题练习 总结 6.指针的好处 总结 7.指针与引用 8.指针与const Q& ...
- 指针的指针(二级指针)本质
可以指向一份普通类型的数据,例如 int.double.char 等,也可以指向一份指针类型的数据,例如 int *.double *.char * 等. 如果一个指针指向的是另外一个指针,我们就称它 ...
- C语言指针--二级指针
文章目录 前言 一.什么是二级指针 二.二级指针的使用 1.二级指针的定义 2.二级指针的赋值 3.二级指针的使用 3.1 用二级指针输出一级指针的地址 3.2 用二级指针输出一级指针中的内容 3.3 ...
- 浅谈auto_ptr智能指针
引入智能指针: 智能指针的实现原理: 资源分配即初始化RAII(Resource Acquisition Is Initialization): 定义一个类来封装资源的分配和释放,在构造函数完成资源的 ...
- 指针java_浅谈Java与指针 - 穿梭于偶然
尽管在java中没有显式的使用 假设People类已经定义,请大家考虑一下面这段代码: People p1 = new People("Csyor"); People p2 = p ...
- 浅谈c语言指针的强制转换
指针是c语言的灵魂,而数据的强制转换是我们在写程序的过程中经常去使用的一种手段,那么这二者结合在一起后会有什么效果呢? 直接上例子说吧 No.1 上面是一段简单的把变量打印出来的程序,显示指针指向地址 ...
- C语言计算机二级考动态分配内存吗,08年计算机二级C语言辅导:malloc动态分配的内存的生存周期是多少?...
malloc动态分配的内存的生存周期是多少??当时直接回答,当然是在调用free进行释放之前阿!!但回头我仔细想过这个问题,在free调用之前那段范围内,但free只有一个指针参数,它是如何知道要释放 ...
最新文章
- android启动第三方应用
- Android app按三层架构+MVC整理(重构)代码可行吗
- python网格搜索核函数_机器学习笔记——模型调参利器 GridSearchCV(网格搜索)参数的说明...
- harris角点检测的学习
- 【译】为什么我更喜欢对象而不是switch语句
- java互喷群,夸夸群和喷喷群的心里需求和投资如此相似
- Jmeter下载安装详细步骤(最新)
- 疫情可视化--2.爬虫--百度迁徙的疫情数据(各省市各个时间段迁入迁出比例)
- WEB前端性能优化总结——如何提高网页加载速度
- 在Ubuntu中安装中文输入法
- 深度学习的权重衰减是什么_深度学习-权重衰减
- poj 3345 Bribing FIPA 树形dp
- 原生JS实现球面展示特效
- NumberRunningTextView(数字会滚动的TextView)
- chrome调试js
- TS2532: Object is possibly ‘undefined‘
- aircrack-ng 添加Mac OS X 支持 airodump-ng和aireplay-ng都可以用了
- 魔幻光影滤镜(2):仿Redfield Fractalius滤镜
- Flutter使用Scaffold报错。
- gazebo如何加载sdf文件的模型