- 浏览: 202741 次
- 性别:
- 来自: 重庆
文章分类
最新评论
二维指针*(void **)的研究(uC/OS-II案例)
- 博客分类:
- c++
原文 : http://blog.csdn.net/fanwei326/article/details/6127091
东莞权智集团 范伟
mail: fanwei326@163.com; wfan@gsl.com.cn
本文若有错误之处,欢迎来信指正。
uC/OS-II内存管理函数内最难理解的部分就是二维指针,本文以图文并茂的方式对二维指针进行了详细分析与讲解。看完本文,相信对C里面指针的概念又会有进一步的认识。
一、OSMemCreate( ) 函数中有如下语句:
OS_MEM *pmem;
INT8U *pblk;
void **plink;
INT32U i;
plink = (void **)addr; //指向所申请内存分区的起始地址
pblk = (INT8U *)addr + blksize; //所申请内存的第二个Block的起始地址
for (i = 0; i < (nblks - 1); i++) //依次申请nblks个Block,链接成单向链表
{
*plink = (void *)pblk;
plink = *plink;
pblk = pblk + blksize;
}
红色部分是初学者对本函数最难理解的部分,因为其用到了二维指针。二维指针就是指向指针的指针,他的内容是一个目标变量的地址,也就是说仍然是一个指针,对二维指针取两次内容才能取到目标变量的内容。这里先复习一下指针的知识:
int a = 5;
int *ptr;
ptr=&a; //ptr指针是地址,指向变量a所在地址。
则可以得出:
*ptr=a; //即指针ptr指向变量a所在地址,*ptr的值就是a的值5
由此类推,对于二维指针变量**plink,指针plink是地址,*plink是plink所指向的地址内的数据,不过同时这个数据也是一个指针,并且**plink是指针(*plink)所指向的地址内的数据。
一维指针所指向的地址内存放的是普通数据,如上述ptr指针所指向的地址内存放的是int型数据5。
二维指针所指向的地址内存放的是一个一维指针,如上述指针plink所指向的地址内存放的是指针*plink。
下面详细分析上述OSMemCreate函数内的语句:
1、plink = (void **)addr;
addr本来是一个一维指针,指向所申请内存分区的起始地址。本句将addr强制转换为二维指针(注意经过强制转换后addr指针本身指向的地址是没有变化的),并将addr地址值赋给plink。则plink的内存中存储的是addr的值,即plink也指向addr所指向的分区起始地址,并且这个地址内存放的内容是指针(*plink),但指针(*plink)还未指向具体的地址。在这条语句之前,这个起始地址内的数据内容是未知的(由编译器分配的)。内存分区结构见下图1所示(假设申请的内存区有4个Block)。
在这个函数当中,我们想把addr指向的二维数组,分割成大小相同的若干块,并用指针把它们链接起来,链接指针放在每个block的首地址。但由于addr是一维指针,它指向的内容不会被解释成一个地址,而是一般的内容。我们要在这些block的首地址内存放指针,所以将addr强制转换成二维指针的目的就是让编译器将addr指向的内容解释成地址,也就是一个指针。
再将addr赋值给plink(让plink去执行连接的操作),使plink与addr指向同一个地址。*plink就是取plink与addr指向地址单元的内容,而这个内容是一个指针,也就是在以前addr指向的地方放上指针*plink。
2、pblk = (INT8U *)addr + blksize;
让pblk指向所申请内存的第二个Block的起始地址,见下图2所示。
因为addr是void型的,要强制转换为INT8U型。
3、*plink = (void *)pblk; //实际上是*plink = pblk,因为pblk是INT8U型的,要强制转换为void型
在for循环内对二维指针plink执行取内容操作(其内容为指针), *plink也是一个指针了(plink指针所代表的地址的内容),将下一个block的首地址赋值给*plink,使它指向的地方改为下一个blcok开始的地址处。
起始地址内的指针*plink被赋值为pblk,所以*plink与pblk一样指向下一个blcok开始的地址处。
如图3所示。
第一个block首地址内的内容为一个指针,该指针指向下一个block首地址。这个地址内存放的就是*plink的内容**plink。
只不过我们并不需要用到这个**plink。
4、plink = (void **)pblk;
功能与plink = (void **)addr 相似,即plink也指向第二个block的起始地址,并且使这个地址内存放的是指针(*plink)。
注意:因为plink所指向的地址变了,此时pblk所指向的地址
内的内容由原来的**plink变为了*plink指针。
并且 *plink还未被赋值,则**plink值是未知的
5、pblk = pblk + blksize;
pblk不断的下移,以指向再下一个block的开始处。
pblk(new)= pblk(old)+blksize
当再次进行for循环时,重复上述过程,利用每个block首地址内的指针将每个Block链接起来组成空闲块链表。
同样,*plink被赋值后,指向pblk所指向的地址,则该地址的
内容为**plink,只不过我们并不需要取出**plink。
6、pmem->OSMemFreeList = addr; /*pmem->OSMemFreeList指向空闲块链表第一个block首地址
在完成for循环后,使pmem->OSMemFreeList指向addr,组成完整的空闲块链表。
总结:进行(void**)强制转换的目的其实就是为了把所指向的地址的内容转换成一个指针。
二、在OSMemGet( )函数内同样有一条强制转换为二维指针的指令:
void *pblk;
执行操作:pmem->OSMemFreeList =*(void **)pblk;
pblk被强制转换为二维指针,然后取出其内容*pblk,也就是pblk地址内存放的链接指针。
意味着取出pblk的内容,由于pblk被强制转换成了二维指针,所以它的内容就不是一般的值,而是一个指针(这个指针指向下一个Block首地址)。
三、在INT8U OSMemPut (OS_MEM *pmem, void *pblk) 函数内同样有类似的指令:
① *(void **)pblk = pmem->OSMemFreeList; // 将欲释放的块添加到空闲块链表最前面
② pmem->OSMemFreeList = pblk;
首先要明白pmem->OSMemFreeList是指向空闲块链表第一个block的首地址的。
语句①将pblk强制转换为二维指针后,再将pmem->OSMemFreeList赋值给pblk的内容(*pblk指针)。根据OSMemPut函数的定义,pblk是函数的形参,是欲释放的块的首地址。所以也就是将pmem->OSMemFreeList指针放入欲释放的块的首地址内,此处强制转换为二维指针的目的就是让欲释放的块的首地址内能存放指针。则这个块的首地址内的指针就是指向原先空闲块链表第一个Block的首地址的,也就是说这个块变成了空闲块链表第一个Block,实现了将释放的块添加到空闲块链表最前面的目的。
然后语句②更新pmem->OSMemFreeList指针,使其指向新释放的块的首地址,这样就保证了pmem->OSMemFreeList始终指向空闲块链表第一个Block首地址。
发表评论
-
C++的原子操作
2012-12-20 17:43 4658在多进程(线程)访问资源时,能够确保所有其他的进程(线程 ... -
匿名namespace的作用以及它与static的区别
2012-12-20 17:24 1771一。匿名namespace的作用 在C语言中,如果我们 ... -
C++类型萃取技术
2012-12-19 15:16 1116Traits技术可以用来获得一个 类型 的相关信息的。 ... -
数值压缩存储方法Varint
2012-12-19 14:35 817转自:http://www.cnblogs.com/smark ... -
TypeList
2012-12-19 13:49 1120转自:http://blog.csdn.n ... -
template <unsigned int N>
2012-12-19 11:51 1466详见:http://stackoverflow.com/ ... -
多级指针和链表
2012-12-18 22:28 0如果看到一个声明:t ... -
理解*(void**)b
2012-12-18 22:03 0#include <stdio.h> ... -
STL标准库:Allocator能做什么
2012-12-18 20:10 0The Standard Librarian: Wha ... -
三种的allocator实现源代码的对比
2012-12-18 19:55 1286转自:http://blog.csdn.net ... -
结构体内变量相对便宜与list_entry()宏
2012-12-18 17:59 906#define list_entry(ptr, t ... -
声明与函数、函数指针---(*(void (*)( ) )0)( ) 解析
2012-12-18 17:33 1083概述 在很 ... -
c++模板(类型依赖)说明例子
2012-12-18 16:57 1130#include <iostream> # ... -
C++中三种new的用法
2012-12-18 16:44 1815我评价自己的C++水平还未入门的确不够准确,应该是远远未 ... -
C++,永久改变你写异常安全代码的方式(神奇的Loki::ScopeGuard)
2012-12-17 20:19 2483作者:Andrei Alexandrescu and P ... -
C++的make_pair函数
2012-12-17 17:19 3435Pairs C++标准程序库中凡是“必须返回两 ... -
C++的explicit构造函数
2012-12-13 15:59 626按照默认规定,只有一个参数的构造函数也定义了一个隐式转换 ...
相关推荐
介绍一种基于uC/OS-Ⅱ的三维运动平台控制系统的实现方案,该系统采用ARM7处理器作为主体,由嵌入式控制系统控制显示、检测、运动等任务。重点对系统的软硬件结构进行详细阐述,给出系统的设计流程,并对系统功能进行简要...
μC/OS-II规定,同处一个分区的内存块的大小必须相等,而且同一个分区内存块的数据类型必须相同。 划分一个内存分区与内存块的方法非常简单,只要定义一个二维数组即可,其中每个一维数组就是一个内存块。例如,...
// vec:用来存储返回集的二维向量 // param-----end-----param // return: 0 查无返回集, // return: >0 返回集的行数, // return: -1001 查无此表 // return: -1002 暂定为Sql语法错误 */ int get_res...
更多网络监控方案,敬请关注维库技术资料网 https://www.dzsc.com/data 引言 进入21 世纪,信息的地位日益重要,对信息的获取和处理能力成为现代信息处理中的关键问题。在人类社会信息化的过程中,借助各种...
对uCOS-II内二维指针的研究,加深对二维指针的理解
二维数组arr与二级指针**arr 个人误区
【测量仪器】TM-3000系列 二维高速尺寸测量仪zip,【测量仪器】TM-3000系列 二维高速尺寸测量仪
第二个均衡化做了N天。。。每天回寝室看一眼以为是算法错了。。后来终于发现是一个溢出的小错误,duang。。这都是假的。。是特技的溢出。。是溢出的特技。。 把读图,写图,灰度,直方图,均值都做成了函数。在main...
这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。 还...
很好的讲解了二维指针,可以看文档自学,很适合初学者。
//******** cloud数据进行VTK三维重建(三角面绘制),并显示 ********// extern "C" int __stdcall ZSY3DDelaunayBuild(bool depth_color); //******** cloud数据进行VTK三维重建(曲面体绘制),并显示 ********// ...
时分法,真正的三维编程,场景渲染 #pragma warning(disable: 4995) #include #include #include // Scenes 场景 #include "Scene.h" #include "StanfordBunnyScene.h" // Include nvstereo, but only for ...
这是自己写的,测试几种二维指针和二维数组的传递方式
积累这我一点一点学习指针的过程 牵扯const的指针我都找出来了 先别说资源垃圾 等你看完再说我垃圾不迟
更多网络监控方案,敬请关注维库技术资料网 http://www.dzsc.com/data 引言 进入21 世纪,信息的地位日益重要,对信息的获取和处理能力成为现代信息处理中的关键问题。在人类社会信息化的过程中,借助各种通信...
下载软件,安装了utorrent可以轻松在六维空间下载高清视频,不再担心流量不够用
二维数组指针分配 形式有多种 可以指定一维 分配一维 也可以不指定都分配
以复杂岛屿地图为例,做了二维A*路径规划。代码为MATLAB代码,解压后可以直接运行。文件夹内AstarCSDN为主文件,TrunToGridMap为地图转栅格文件,child_nodes_cal为计算子节点的函数,1234d.jpg为地图图片。
利用matlab实现雷达目标的有序统计恒虚警检测。
机械制图表面粗糙度的标注最新国家标准,GB/T131-2006