当前位置:首页 > 经典书库 > 工程师手册

指针和数组

书籍:工程师手册

出处:按学科分类—工业技术 企业管理出版社《工程师手册》第859页(4190字)

指针变量存贮的是某一数据的地址,而不是数据本身。指针的使用常与数组元素的处理(赋值或修改)紧密相关。指针主要有三方面的用途:

(1)指向数组的不同数据元素;

(2)允许程序运行时创建新的变量(动态存贮分配);

(3)访问某一数据结构的不同单元。

本节讨论指针的前两种用途,第三种用途将在3.3.7节讨论。

1.特殊指针操作符

有效地使用指针需要两个特殊的指地操作符:间址操作符(*)和取样地址操作符(&)。当要获取指针所指地址中存贮的数据时,需要使用间地址符(*),参看下述程序:

本程序声明i为整数,ptr为指向整数变量的指针。首先i被赋值为7。然后语句ptr=&i;使ptr指向i的地址。编译器变量i和ptr在存贮器中分配了存贮单元,运行时ptr被设置为整数变量i的起始地址,上述程序利用函数printf以下两种不同方式打印i的整数值--一是直接打印变量i的内容(printf(“\n%d,i),),一是利用址符(printf(“\n%d,*ptr),)。ptr前的操作符*指导编译器将存贮在地址ptr(即整数i的地址)中的值转送给printf函数。如果没有址符f*,则赋值给ptr的地址而不是其中的值将被函数printf显示。上例的最后两行说明了间址存贮,地址ptr中的数据改为11,这样相当于改变i的值。因为ptr指向i的地址。

数组本质上是由编译器分配的一块连续存贮区,其名称由声明语句给出。实际上,数组名不过是指向数组起始地址的一个固定指针。在C中,数组名既可作为指针用,也可用来引用数组元素(如a[2])。如果a声明为某种类型的数组,则*a和a[0]是等价的。而且*a(a+i)和a[i]也相同(只要i声明为整数),当然a[i]的意思更清楚一些,通过指针和增量操作符(++),可以快速地顺序访问数组的所有元素,例如,下述三个语句将数组a的前100个元素设置10:

int*pointer;

pointer=a;

for(i=0;i<100;i++) *pointer++=10;

在很多计算机上,上述代码比单个语句for(*i=0;i<100;i++)a[i]=10执行得快。因为指针的后增量比数组下标的计算快。

2.指针与动态存贮分配

C语言有四个标准函数允许程序员动态地改变变量和数组的类型及大小。C程序能将同一存贮区用于不同目的,以免浪费存贮单元。另外,自动变量在函数(或大括号内的一段包含该变量声明的代码)开始运行时被自动从栈中分配存贮空间,在函数退出运行时(或右括号}处)又自动释放所占空间。只要合理使用自动变量和动态存贮分配函数,C程序占用的存贮空间几乎不多于程序每步运行所必须的存贮量。C的这一特点在多用户环境下尤其重要,因为这时用户申请的存贮量与占用存贮的时间之乘积将最终决定系统性能。在很多DSP应用中,合理运用动态存贮分配技术,可以用内部存贮量很小的廉价单片信号处理器完成复杂的函数运算,而不必采用带大容量片外存贮的昂贵处理器。

C用四个标准函数处理一个程序可获得的存贮空间(有时称为堆,以与栈相区别),其中malloc按字节分配存贮器,calloc按长度为任意个字节的项分配存贮器,free从堆中释放以前分配的项,reallo改变以前分配的项的大小。

当使用以下函数时,要分配存贮空间的项的大小也必须传送给这些函数,分配函数然后返回一个指向一块贮区的指针。该存贮区的大小应满足要求,为了使利用存贮分配的代码于移植,必须使用编译器的内部宏sizeof。例如:

int*ptr

ptr=1(int*)malloc(sizeof(int));

以上代码为一个整数分配存贮,并用整数指针ptr指向所分配的存贮块的首址。在32位机上该存贮块占四个字节。在16位机上一般只占用两个字节。由于malloc(以及calloc和realloc)返回字符指针,必须用强制符(int*)将它强制为整数指针类型。类似地,用calloc和一个指针array,可以定义一个含25个元素的整数数组:

int*array;

array=(int*)calloc(25,sizeof(int));

上述语言将分配一个有25个元素的数组,每个元素的大小等于回标机上整数的大小。通过另一指针,(改变指针pointer是不明智的,因为它保存着所分配存贮区的首址,)可以引用数组元素,或通过下标形式arrayp[[i](0<i<24)引用,由calloc分配存贮区的初始值为0。

函数malloc,calloc和free组成了一个简单的通用存贮分配包。free的参数(强制为字符指针)是指向以前由malloc或calloc分配的存贮块的指针,free释放相应存贮块的内容。malloc分配的空间运行时溢出或向free传送一随机数都会引起混乱。由于程序运行中释放的存贮空间总是交给操作系统管理,所以free没有返回值。

realloc改变以前分配的存贮块的大小并返回指向存贮块的指针。存贮器中原来的内容不变。realloc比malloc使用得少,因为通常数组的大小事先知道。但是,如果上例中分配的含25个元素的数组要扩展为100个元素,则须使用以下语句:

array=(int*)realloc((char*)array,100*sizeof(int));

realloc与malloc类似,其参数为需分配的字节数。要特别注意下面两个语句与前面的reaHoc语句不等价:

free((char*)array);

array=(int*)calloc(100,sizeof(int);

这两个语句确实能将25个元素的数组改变为100个元素的数组,但却不能保持前25个元素的值不变。事实上,calloc将100个整数都初始化为o,而realloc将保持前25个整数值,剩余的75个数元素不作任何设置。

如果没有存贮空间可供分配。malloc,realloc和caHoc返回空指针(值为0)。当reallocf返回0时,原指针所指的存贮区也可能被破坏掉。

3.指针数组

C语言的任一数据类型或任一数组类型的指针都可以构成数组。指针数组对于访问大的矩阵非常有用。一个由10个指针组成的数组,其中每个指针指向20个整数,可以动态分配如下:

int*mat[10];

inti;

for(i=0;i<10:i++){mat[i]=(int*)calloc(20,sizeof(int));

if(!mat[i]){

printf(“\nError in matrix allocation\n”);

exit(1);

在上述代码中,先声明了一个含10个整数指针的数组.然后使每个指针分别指向由10次连续调用calloc分配的不同存贮块。每次调用callocf之后,都要检查指针以确保获得所需要存贮空间(如mat[i]为空指针。则!mat[i]为true)。通过指针和间址符可以访问矩阵mat的每个元素。例如,*(mat[i]+j)表示第i行,(0<i<9),第j列(0<j<19)的矩阵元素,它等价于mat[i][j]。事实上,前述代码就等价于(少在mat被引用的方式上)数组声明int mat[10][20],不过mai[10][20]是分配在栈中的自动变量,而对calloc的调用将mat的空间分配在堆中。当然,对分配在栈中的自动变量mat不能使用free和realloc.

访问二维矩阵的某一元素(如使用mat[i][j])通常比用指针访问同一矩阵元素需要更多的指令和运行时间。当频繁引用矩阵的同一行或列时尤如此,但是对有些编译器和针操作较慢的目标机,利用指针访问向二维数组可能需要与如a[i][j]这种访问同样多的时间。

分享到: