微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 二维指针*(void **)的研究(uC/OS-II案例)

二维指针*(void **)的研究(uC/OS-II案例)

时间:09-12 来源:互联网 点击:

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**)强制转换的目的其实就是为

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top