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,完成了将开释的块添加到闲暇块链表最前面的意图。