计算机第8章 指针_第1页
计算机第8章 指针_第2页
计算机第8章 指针_第3页
计算机第8章 指针_第4页
计算机第8章 指针_第5页
已阅读5页,还剩121页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第8章指针

第8章指针

8.1指针的概念

8.2指针变量的定义与引用

8.3指针运算

8.4指针和数组

8.5指针与字符串

8.6指针数组和指向指针的指针

8.7指针与内存的动态分配

8.8指针与数卵.作为函数的参数

8・9带参数的main函数

8.10返回指针侑的函数

8.11函数指针的定义与引用

8.12本章小结

,Bdck4

第8章指针---------------------------------

8.1指针的概念

8.1.1变量的地址与变量的内容

计算机为了方便管理内存,为每一个内存单元都

编了号,这个编号称为内存单元的地址。一般把存储

器中的一个字节称为一个内存单元(亦称存储单元),变

量的地址与变量的内容是两个不同的概念。变量在内

存中所占存储空间的首地址就称为变量的地址。而变

量在内存所占的内存单元中存放的数据就称为变量的

内容。

,Bdck4

盛露第8章指针_________________________________

8.1.2直接访问与间接访问

变量值的存取都是通过地址进行的,例如:

priintf(''%d〃,&i)的执行是这样的。先找到变量i的地址

200,然后从200开始的两个字节中取出数据(假若变

量i的值为5)把它输出。这种按变量地址存取变量的

方式称为直接访问方式。还可以采用另一种称为间接

访问方式,将变量i的地址存放在另一个变量中。假设

一个变量P,用来存放变量i的地址,它被分配为300,

301两个单元。将i的地址存放到p中,要存取变量i的

值,先找到存放i地址的变量P,从P中取出i的地址

(200),然后到200,201中取出i的值5。

<Bdck<

茎0第8章指针

8.1.3指针与指针变量

对于一个内存单元来说,单元的地址即为指针,

其中存放的数据是该单元的内容。在C语言中,允许用

一个变量来存放指针,这种变量称为指针变量。因此,

一个指针变量的值就是某个内存单元的地址,或称为

某内存单元的指针。

,Bdck4

茎0第8章指针

PC

II

0110H।----------力

0110H(地址)

图8.1指向变量C的指针变量P

,Bdck4

热第8章指针_________________________________

如图8-1所示,设有字符变量C,其内容为K

(ASCII码为十进制数75),C占用了0110H号单元(地址

用十六进制表示)。当有指针变量P,内容为0110H时,

我们称为“P指向变量C〃或者“P是指向变量C的指

针”。

严格地说,一个指针是一个地址,是一个常量,

而一个指针变量却可以被赋予不同的指针值,是变量。

但通常把指针变量简称为“指针”。为了避免混淆,

我们约定:“指针”是指地址,是常量,“指针变量”

是指取值为地址的变量。定义指针的目的是为了通过

指针去访问内存单元。

<Bdck<

盛露第8章指针_________________________________

既然指针变量的值是一个地址,那么这个地址不

仅可以是变量的地址,而且也可以是其他数据结构的

地址。在一个指针变量中存放一个数组或一个函数的

首地址有何意义呢?因为数组或函数都是连续存放的,

所以通过访问指针变量取得了数组或函数的首地址,

也就找到了该数组或函数。这样一来,凡是出现数组、

函数的地方都可以用一个指针变量来表示,只要该指

针变量中赋予数组或函数的首地址即可。这样做,将

会使程序的概念十分清楚,程序本身也精练、高效。

,Bdck4

盛露第8章指针_________________________________

在C语言中,一种数据类型或数据结构往往都占

有一组连续的内存单元。用“地址”这个概念并不能

很好地描述一种数据类型或数据结构,而“指针”虽

然实际上也是一个地址,但它却是一个数据结构的首

地址,它是“指向”一个数据结构的,因而概念更为

清楚,表示更为明确。这也是引入“指针”概念的一

个重要原因。

,Bdck4

函露第8章指针

8.2指针变量的定义与引用

821指针变量的定义

指针变量定义的一般形式为

类型说明符*指针变量名;

其中,*为说明符,表示这是一个指针变量;指针

变量名为用户自定义标识符;类型说明符表示该指针

变量所指向的变量的数据类型。

,Bdck4

遍露第8章指针

例如:

int*pl;

该定义表示pl是一个指针变量,它的值是某个整

型变量的地址,或者说pl指向一个整型变量。至于pl

究竟指向哪一个整型变量,应由向pl赋予的地址来决

定。对于指针变量的类型说明应包括以下三个方面的

内容:

(1)指针类型说明,即定义变量为一个指针变量。

(2)指针变量名。

(3)变量值,即指针变量所指向变量的地址。

,Bdck4

茎0第8章指针

例如:

staicint*p2;

/*p2是指向静态整型变量的指针变量*/

float*p3;/*p3是指向浮点型变量的指针变量*/

char*p4;/*p4是指向字符型变量的指针变量*/

应该注意的是,一个指针变量只能指向同类型的

变量,如P3只能指向浮点型变量,不能时而指向一个

浮点型变量,时而又指向一个字符型变量。

,Bdck4

盛露第8章指针_________________________________

8.2.2指针变量的引用

指针变量同普通变量一样,使用之前不仅要定义

说明,而且必须赋予具体的值。未经赋值的指针变量

不能使用,否则将造成系统混乱,甚至死机。同时,

指针变量的赋值只能赋予地址,决不能赋予任何其他

数据,否则将引起错误。

在C语言中,初始变量的地址是由编译系统分配

的,对用户完全透明,用户不知道变量的具体地址。

,Bdck4

盛露第8章指针_________________________________

C语言中提供了地址运算符&来表示变量的地址。

其一般形式为

&变量名

如&a表示变量a的地址,&b表示变量b的地址。变

量本身必须预先说明或定义。

设有指向整型变量的指针变量P,如要把变量a的

地址赋予p可以有以下两种方式:

(1)指针变量初始化的方法:

inta;

int*p=&a;

,Bdck4

盛露第8章指针_________________________________

(2)赋值语句的方法:

inta;

int*p;

p=&a;

不允许把一个数赋予指针变量,如下面的赋值是

错误的:

int*p;

p=1000;

被赋值的指针变量前不能再加"”说明符,如写

为*p=&a也是错误的。

,Bdck4

盛露第8章指针_________________________________

8.3指针运算

8.3.1指针变量的算术运算

指针变量可以进行某些运算,但其运算的种类是

有限的:如部分算术及关系运算。

设px与py是指向具有相同类型且连续存储的一组数

据。如指向同一个数组。若n代表整数,则指针可进行

下列加减运算。

px±n,px++,px--,++px,--px,px-py;py-px;

(1)px+n.就是“px的地址土n*px的类型占用的单

元数”所对应的地址。

,Bdck4

函露第8章指针

(2)px++,++px,px—,一px.显然是px±n的特

(n=l)o即指针加1或减1。

(3)px-py,py-px两个指针相减运算结果

是整数,即它们所指向数组元素下标相差的整数。

设px指向数组元素a[2],py指向数组元素a[6],则

下列表达式及其运算结果:

px-py结果为整数-4。

py-px结果为整数4o

<Bdck<

挑第8章指针_________________________________

【例8.1】指针变量的定义、赋值及简单应用

main()

{inta=5,*p=&a;

printf(”%d”,*p);

)

程序运行情况:

5

程序说明:在定义指针变量p后,利用指针变量p

取得整型变量a的地址,并在最后的输出中,利用指针

变量获取变量a的值进行输出。

<Bdck<

盛露第8章指针_________________________________

8.3.2指针的关系运算

它的运算规则是:当两个指针变量的值(地址值)

潢足关系运算时,结果为1(真);否则结果为0

(假),所以两个指针变量进行关系运算的结果也是

逻辑值。

定义了数组a和同类型的指针变量px,py;使px指向数

组元素a[l];py指向数组元素a[4]。请看下列的关系

表达式及其运算结果:

px<py结果为1(真)。

px++==py结果为0(假),注意++是后缀。

,Bdck4

茎0第8章指针

_py==pX+2结果为1(真),注意-是前缀。

py<&a[5]结果为1(真),&a[5]地址是地址常量。

py>=px+2结果为1(假),px+2是地址型表达式,

代表a[3]的地址。

指什的运算应注意以下几点:

・指什变量只能和整数或整型变量相加减,而不能和

实型数或实型变量相加减。如px+3.5是错误的

•指什变量不能进行乘法和除法运算。如py*4或py/2

都是错误的。

两个指什变量相减,必须指向同一个数组,否则不能进

行减法运算。

,Bdck4

函露第8章指针

8.4指针和数组

8.4.1指针与一维数组

定义一个整型数组和一个指向整型的指针变量如下

inta[10],*p;

假定给出赋值运算

p=&a[O];

此时,p指向数组中的第0号元素,即a[0],指针变量p中包

含了数组元素a[0]的地址,由于数组元素在内存中是连

续存放的,因此,我们就可以通过指针变量p及其有关运

算间接访问数组中的任何一个元素。

,Bdck4

函露第8章指针

则表示元素地址还可以用a+i,p+i,&p[i],

表示数组中元素a[i],还可以用p[i],*(a+i),*(p+i)。

下面我们用指针给出数组元素的地址和内容的几种表示形式。

(1)p+i和a+i均表示的地址,它们均指向数组第i号元

素,即指向a[i]0

(2)*(p+i)和*(a+i)都表示p+i和a+i所指对象的内容,

即为a[i]o

(3)指向数组元素的指针,也可以表示成数组的形式,也

就是说,它允许指针变量带下标,如p[i]与*(p+i)等价。

<Bdck<

盛露第8章指针_________________________________

【例8.2]数组与指针变量的综合应用举例。

方法1:用下标法引用数组元素。

main()

{inta[10],i;

for(i=0;i<10;i++)

nn

scanf(%d?&a[i]);

for(i=0;i<10;i++)

printf(n%d\a[i]);

,Bdck4

/露第8章指针_________________________

方法2:用指针变量法引用数组元素。

main()

{inta[10]/p,i;

p=a;

for(i=0;i<10;i++)

scanf(”%d”,p+i);

for(i=0;i<10;i++)

printf(n%dn,*(p+i));

,Bdck4

盛露第8章指针_________________________________

方法3:通过指针变量自增运算引用数组元素。

main()

{inta[10]/p;

fbr(p=a;p<a+10;p++)

scanf(n%dn,p);

fdr(p=a;p<a+10;p++)

printf(”%d”,*p);

,Bdck4

揶第8章指针______________________________

方法4:用指针的下标表示法引用数组元素。

mainQ

{inta[10],*p,i;

p=a;

for(i=O;i<10;i++)

scanf(n%dn,&p[i]);

fbr(i=O;i<10;i++)

printf(n%dn,p[i]);

}

程序运行结果为:

1234567890/

1234567890

<Bdck<

盛露第8章指针_________________________________

8.4.2指针与二维数组

用指针可以指向一维数组,也可以指向二维数组。

1.二维数组的地址

为了说明问题,我们定义以下二维数组:

inta[2][4]={{0,l,2,3},{4,5,6,7}};

a为二维数组名,此数组有3行4列,共12个元素。但也可这

样来理解,数组a由二个元素组成:a[0]9a[l]o而它们中

每个元素又是一个一维数组,且都含有4个元素,例如,

a[0]所代表的一维数组所包含的4个元素为

a[0][l],a[0][2],a[0][3]o

,Bdck4

茎0第8章指针

如图8.2所示:

a[0]0.123

a[l]4567

图8.2a[O],a[l]代表二维数组中的行

但从二维数组的角度来看,a代表二维数

组的首地址,当然也可看成是二维数组第0

行的首地址。a+1就代表第1行的首地址。

如果此二维数组的首地址为1000,由于第0

行有4个整型元素,所以a+1为1008。如图

8.3所示

<Bdck<

第8章指针_________________________

a[0]a[O]+la[0]+2

a[0]+3

a►1000100210041006

0123

a+4-----a1008101010121014

4567

图8.3二维数组中的行地址和列地址示意图

二维数组元素明口]可表示成*(咽+j)或

*(*(a+i)+j),它们都与a[i]用等价,或者还可写成

(*(a+i))[j]o见表8.1

,Bdck4

茎0第8章指针

表8.1指针变量的含义及对应地址

含义地址

a一维数组首地,0行首地1000

a[O]+O,*(a+O),*a表第0行第0列兀素地址1000

a+l,a[l]第1行首地址1008

a[l]+2,*(a+l)+2,&a[l][2]第1行第2列兀素地址1012

*(a[l]+2),*(*(a+l)+2),第1行第2列兀素的值6

a[l][2]

*(a[i]+j),*(*(a+i)+j),a[i]U]第i行第j列元素的值

,Bdck4

盛露第8章指针_________________________________

另外,要补充说明一下,如果你编写一个程序输出打

印2和*%你可发现它们的值是相同的,这是为什么呢?

我们可这样来理解:首先,为了说明问题,我们把二维数

组人为地看成由两个数组元素a[0],a[l]组成,将a[0],

a[l]]看成是数组名它们又分别是由4个元素组成的一维

数组。因此,a表示数组第0行的地址,而*a即为a[0],它

是数组名,当然还是地址,它就是数组第0行第0列元素

的地址。

,Bdck4

盛露第8章指针___________________________________

2指向二维数组的指针变量

在了解上面的概念后,可以用指针变量指向二维数组及其元素。

(1)指向数组元素的指针变量

【例8.3]用指针变量输出数组元素的值。

mainQ

{staticinta[2][4]={1,2,3,4,5,6,7,8};int*p;

fbr(p=a[O];p<a[0]+8;p++)

{if((p-a[0])%4=0)printf(n\nn);printf(n%4dn,*p);}

}

程序运行结果为:

1234

5678

<Bdck<

盛露第8章指针___________________________________

如果读者对p的值还缺乏具体概念的话,可以把p的值(即数组

元素的地址)输出。若将程序最后两行改为:

printf("元素地址=%o,元素值=%4d\n”,p,*p);

这时输出如下:

元素地址=236,元素值=1

元素地址=240,元素值=2

元素地址=242,元素值=3

元素地址=244,元素值=4

元素地址=246,元素值=5

元素地址=250,元素值=6

元素地址=252,元素值=7

元素地址=254,元素值=8

<Bdck<

盛露第8章指针_________________________________

计算用]口]在数组中的相对位置的计算公式为:

i*mtj

其中m为二维数组的列数(二维数组大小为n*m).例如,

对3*4(3行4列)的二维数组,它的第2行第3列元素

(a⑵[3])对a[0][0]的相对位置为2*4+3=11。

可以看到,C语言规定数组下标从0开始,对计算上述

相对位置比较方便,只要知道i和j的值,就可以直接用

i*m+j公式计算出相对于数组开头的相对位置。如

果规定下标从1开始,则计算[j]的相对位置所用的公

式就要改为:(i-l)*m+(j-1),这就增加了计算的工作量。

,Bdck4

茎0第8章指针

(2)指向由.m个整数组成的一维数组的指针变量

这里的指针变量P不是指向整型变量,而是指向一个

包含m个元素的一维数组。如果p先指向a[0],贝1Jp+1

不是指向而是指向a[l],p的增值以一维数

组的长度为单位,见图8.4

P.a

----------------

S[口]

.------------

p+2敲1]

-----A---------

或一

国QZL指向皿个元素的一k

绍&4维数组的指针变量

<Bdck<

函露第8章指针

【例8.4】输出二维数组任一行任一列元素的值。

main()

{inta[3][4]={l,3,5,7,9,HJ3,15,17,19,21,23};

int(*p)[4],ij;

p=a;

scanf("i=%d,j=%d”,&i,&j);

,n

printfCa[%d][%d]=%d\n?i?j,p[i]|j]);

<Bdck<

盛露第8章指针_________________________________

程序运行结果为:

i=l,j=2/(本行为键盘输入)

a[l][2]=13

程序第三行“int(*p)[4『表示P是一个指针变量,它指向包

含4个元素的一维数组。注意*P两侧的括号不可缺少,如

果写成*P[4],由于方括号口运算级别高,因此P先与[4]结

合,是数组,然后再与前面的*结合,*p[4]是指针数组

(参看本章8.6).有的读者感到"(*p)[4]〃这种形式不好

理解。

程序的p+i是二维数组a的第i行的地址,*(p+2)+3是a

数组第2行第3列元素地址,这是指向列的指针,

*((*p+2)+3)是a[2][3]的值。

,Bdck4

盛露第8章指针_________________________________

8.5指针与字符串

8.5.1字符串的表示与引用

在C语言中,既可以用字符数组表示字符串,也可用

字符指针变量来表示;引用时,既可以逐个字符引用,

也可以整体引用。

前面章节中介绍了用字符数组来表示字符串,以及

对字符的引用。本节重点介绍利用字符指针变量对字符

串的表示和引用。

,Bdck4

盛露第8章指针_________________________________

1逐个引用

【例8.5】使用字符指针变量表示和引用字符串。

main()

{char*string="Beijing2008.n;

while(*string!-\0!)

{print4"%c",*string);string++;}

printf(n\n\nn);

)

程序运行结果为:

Beijing2008.

,Bdck4

函露第8章指针

注意:

(1)字符指针变量string中,仅存储串常量的首地

址、而串常量的内容(即字符串本身)存储由系统自动

开辟的内存中,并在串尾添加一个结束标志'\0'。

(2)若定义了一个指针变量,使它指向一个字符串

后,可以用下标形式引用指针变量所指的字符串中的字

符。如:

,Bdck4

盛露第8章指针_________________________________

【例8.6]

#include"stdio.h"

main()

{char*a="Beijing2008.”;

inti=0;

printff'Thelengthofthestringis%d\nn,strlen(a));

while(a[i]!='\0')

{putchar(a[i]);i++;}

putchar(,\n,);

,Bdck4

第8章指针---------------------------------

程序运行结果为:

Thelengthofthestringis13

Beijing2008.

2整体引用

【例8.71对【例8.6】采取整体引用的办法。

main()

{char*string="Beijing2008.n;

nn

print%s\n9string);

,Bdck4

盛露第8章指针_________________________________

程序运行结果为:

Beijing2008.

说明:printf("%s\n\string);语句通过指向字符串的

指针变量string,整体引用它所指向的字符串。其原

理是:系统首先输出string指向的第一个字符,然后

使string自动加1,使之指向下一个字符;重复上述过

程,直至遇到字符串结束标志。

显然,对于字符串输出而言,整体引用比逐个字

符引用更简洁。

,Bdck4

盛露第8章指针_________________________________

3字符指针变量与字符数组的比较

虽然用字符指针变量和字符数组都能实现字符串的存储

和处理,但二者是有区别的,不能混为一淡。

(1)存储内容不同

字符指针变量中存储的是字符串的首地址,而字符数组

中存储的是字符串本身(数组的每个元素存放一个字

符)。

(2)赋值方式不同

对于字符指针变量,可采用下面的赋值语句赋值:

char*p;

p="Howareyou!,r;

,Bdck4

盛露第8章指针----------------------------

(3)指针变量的值是可以改变的,字符指针变量也不例

外,而数组名代表数组的起始地址是一个常量,而常量

是不能被改变的。

例如:char*p="Howareyou!";

p=p+3;

printf(n%s",a);

针变量a的值可以变化,输出字符串从当前所指向的

单元开始输出各个字符,直到'\0,为止,而数组名代表

地址,但它的值是不能改变的。以下为错误赋值。

charstr[]二〃Howareyou!〃;

str=str+3;/*不能给常量赋值*/

,Bdck4

函露第8章指针

8.6指针数组和指向指针的指针

8.6.1指针数组

其元素均为指针类型数据的数组,称为指针数组。指针

数组中的每一个元素都相当于一个指针变量,且这些指

针变量指向相同数据类型的变量。

指针数组定义的一般形式为:

类型名*数组名[整型常量];

其中,“整型常量”规定了指针数组的长度,类型名则

代表指针数组元素可以指向的数据类型。

,Bdck4

茎0第8章指针

例如,

int*p[6];

由于[]比*优先级高,因此p先与[6]结合,形成p[6]形

式,这显然是数组形式,它有6个元素,然后再与前面的

结合表示此数组是指针类型的,每个数组元

素(相当于一个指针变量)都可以指向一个整型变量。

即p有6个元素的数组,每个元素是一个指向int类型数据

的指针。

注意:int*p注]与int(*p)[6],请读者自行分析。

<Bdck<

盛露第8章指针_________________________________

【例8.8]编程将如下表示地址名的字符串按字母顺序由小

到大排序,然后输出这些字符串:Beijing,Shanghai,

Nanchang,Guangzhouo

#include"stdio.h"

main()

{intij;chartemp[10];

charstr[4][10]=

{"Beijing"JShanghai"JNanchang"JGuangzhou''};

printff'Beforesorted:\nn);

for(i=0;i<4;i++)printf,%s,9\str[i]);/*输出排序前

的5个字符串*/

,Bdck4

盛露第8章指针_________________________________

/*交换法排序*/

for(i=0;i<3;i++)

for(j=i+l;j<4;j++)

if(strcmp(str[j],str[i])<0)

{/*则交换str[j]所指字符串和str[i]所字符串*/

strcpy(temp,str[i]);

strcpy(str[i],str[j]);

strcpy(str[j],temp);

<Bdck<

函露第8章指针

printff'\nAftersorted:\nn);

for(i=0;i<4;i++)printf(n%s,n,str[i]);/*输出排序

后的4个字符串*/

)

程序运行结果为:

Beforesorted:

Beijing,Shanghai,Nanchang,Guangzhou,

Aftersorted:

Beijing,Guangzhou,Nanchang,Shanghai,

,Bdck4

热第8章指针_________________________________

对于二维数组与指针数组之间的区别初学都有常常会感到

困惑,例如:

charstr[4][10]={"Beijing","Shanghai",

"Nanchang","Guangzhou”};

char*ptr[4]={"Beijing","Shanghai",

"Nanchang"/Guangzhou”};

虽然str[i]和ptr[i]都代表第i+1个字符串的首地址,都是对第

i+1字符串的合法引用,但str与ptr的含义却又完全不同:

,Bdck4

函露第8章指针

str代表一个真正的二维数组,str是它的

名字,编译时需分配4*10个字节的存储空间

用于存放40个字符型数据,同时将初绍化列

表中提供的字符串赋值给字符数组的元素,

而对于指针数组ptr只需分配4个用于存放指

针型数据的存储单元即可。

,Bdck4

函露第8章指针

8.6.2指向指针的指针

指向指针数据的指针变量,简称为指向指针的指针。

定义一个指向指针数据的指针变量,格式如下:

类型符**指针变量;

如:char**p;

p的前面有两个*号。*运算符的结合性是从右到左,因此

**p相当于*(*p),显然*p是指针变量的定义形式。

,Bdck4

函露第8章指针

861节中介绍了指针数组,该类数组中的元

素是指针型数据,故指针数组中的元素也可看作

是指向指针的指针,即所谓的二级指针变量。

下面举例说明指针数组和指向指针的指针的

使用方法。

,Bdck4

函露第8章指针

【例8.9】指针数组与指向指针的指针使用举例。

main()

{char*name[]={"Followme"JBASIC","GreatWall",

"FORTRAN”「'computerdesign"};

char**p;

inti;

for(i=0;i<5;i++)

{p=name+i;printf,%s\n”,*p);}

,Bdck4

盛露第8章指针_________________________________

运行结果如下:

Followme

BASIC

FORTRAN

GreatWall

Computerdesign

程序说明:p是指向指针的指针变量,在第一次执行循环

体时,赋值语句“p=name+i;”使p指向name数组的0号元

素name[0],*p是name[0]的值,即第一个字符串的起始地址,

用printf函数输出第一个字符串(格式符为%s),依次输出

5个字符串。

<Bdck<

盛露第8章指针_________________________________

指针数组的元素也可以不指向字符串,而指向整型数

据或实型数据等,例如:

inta[5]={l,3,5,7,9};

int*num[5]

int**p;

for(i=0;i<5;i++)

num[i]=&a[i];

例8.10是一个指针数组的元素指向整型的简单例子。

,Bdck4

盛露第8章指针____________________________

【例8.10】

main()

{staticinta[5]={l,355,7,9};

staticint*num[5]={&a[0],&a[l],&a[2],&a[3],&a[4]};

int**p,i;p=num;

for(i=0;i<5;i++)

{printf("%d\t",**p);p++;}

}

运行结果为:

13579

,Bdck4

函露第8章指针

8.7指针与内存的动态分配

c语言有两种分配内存的方式:

静态内存分配方式和动态内存分配方式。

静态内存分配方式:

是指所占用的数据存储位置和字节数在程序运行过程

中是固定不变的。

缺点是:对于事先无法准确估计数据量的情况下,无

法做到既满足处理需要,又不浪费内存空间。

,Bdck4

函露第8章指针

动态内存分配方式:

是指在程序运行过程中,根据程序的实际需要分配

一块大小合适的内存。程序可以动态地分配给一个数

组,也可以动态地分配给其它类型的数据单元。动态

分配的内存只需要一个指针变量,记录内存的地址。

优点是:动态内存区能用于不同的任务。对于一个

任务分配占用了的内存,当该任务完成以后就可释放

并收回,以后又可再把它们重新分配给其它的任务使

用。

,Bdck4

第8章指针

下面就介绍C语言编译系统库函数提供的有关动态内存

分配的几个函数。

1malloc()函数

调用方式:

void*malloc(unsigenedsize)

功能:在内存的动态存储区中分配一个长度为size个字

节的连续空间。此函数的返回值是一个指向分配域起始地

址的指针(基类型为void),若此函数未能调用成功(例

如,内存空间不足),则返回空指针(NULL)。

,Bdck4

盛露第8章指针_________________________________

如果要将函数调用的返回值赋给某个指针,则应根

据该指针的类型将返回值进行强制类型转换。

例如:

int*pl;

pl=(int*)malloc(10);

其中,malloc(10)表示申请了一个长度为10个字节的存储

空间。malloc(10)的返回值经强制类型转换后赋给指针

变量pl,即执行语句pl=(int*)malloc(10)后,表示用一个

指向int数据的指针变量pl指向了这段存储空间的首地址。

,Bdck4

盛露第8章指针_________________________________

2colloc()函数

调用方式:

void*colloc(unsigenedn,unsigenedsize)

功能:在内存的动态存储区中分配n个长度为size个字

节的连续空间。此函数的返回值是一个指向分配域起始

地址的指针(基类型为void),如果分配不成功,则返回

空指针(NULL),若要将返回值赋给某个指针,要进行

强制类型转换。例如:

float*p2;

p2=(float*)calloc(10,sizeof(float));

<Bdck<

蓝露第8章指针_________________________________

表示系统申请了10个连续的float类型的存储单元,并用

指针p2指向连续存储单元的首地址。

3firee()函数

调用方式:

voidfree(void*p)

功能:释放由p指向的内存区,使这部分内存区能被其

它变量使用,该函数无返回值。

例如,为将前面已申请的指向整型数据的指针pl,所指

向的确10个字节的存储空间释放掉,可使用下列语句:

free(pl);

,Bdck4

盛露第8章指针_________________________________

【例8.12】编程输入一个班的某课程的学生成绩,计算其

平均分,然后输出。班组人数由用户用键盘输入。

程序如下:

#include<stdio.h>

#include<stdlib.h>

main()

{int*p,n,i,sum;

printff'Pleaseenterarraysize:");

scanf(n%dn,&n);/*输入学生人数*/

,Bdck4

函露第8章指针

p=(int*)malloc(n*sizeof(int));/*向系统申请n个sizeof(int)字节的连续

存储空间*/

printf(nPleaseenterthescore:11);

for(i=0;i<n;i++)/*输入每个学生的分数*/

scanf(n%dn,p+i);/*累加变量sum赋初值*/

sum=0;

fdr(i=0;i<n;i++)

sum=sum+*(p+i);/*计算总分数*/

printff''aver=%d\n:,sum/n);/*打印平均分*/

free(p);/*释放向系统申请的存储空间*/

<Bdck<

盛露第8章指针_________________________________

程序运行结果如下:

Pleaseenterarraysize:5/

Pleaseenterthescore:9085709580

aver=84

说明:

⑴malloc()和calloc()函数是动态内存分配函数,

如果分配失败则返回空指针,所以可以检查是否分配

成功。若分配失败可用exit(l)函数终止程序运行。

,Bdck4

函露第8章指针

(2)free。函数只能用于已由malloc()和colloc()

分配地址的指针来调用。如用其它指针来调用则可

能破坏内存管理机制,造成对系统的破坏。

⑶malloc()>caolloc()>free()函数原形

对于ANSI标准在“stdlib.h”头文件中,而其它C编

译则在“alloc.h”头文件中。

,Bdck4

函露第8章指针

8.8指针与数组作为函数的参数

8.8.1指针变量作为函数的参数

指针变量,既可以作为函数的形参,也可以作为

函数的实参,指针变量作实参时,与普通变量一样,也

是〃值传递〃。即将指针变量的值传递给调函数的形

参。但由于指针变量的值是一个地址,实际是实现

“地址的传递”。

,Bdck4

遍露第8章指针

【例8.13】

mainQ

{voidsub(int*px,int*py)

intx=8,产11;

nn

printf(%d,%d\n,x?y);

sub(&x,&y);

nn

printf(%d,%d\n,x?y);

<Bdck<

函露第8章指针

voidsub(int*px,int*py)

{*px=10;

*py=20;

}

运行结果:

8,11

10,20

<Bdck<

盛露第8章指针_________________________________

说明:

对sub()函数调用时,实参是x变量的地址和y变量

的地址,它们分别传递给指针变量px和py,即参数传

递后px指向x变量.py指向y变量,执行*px=10;

*py=20;语句后把px地址的内容赋值为10,py地址内

容赋值为20。函数调用结束后,这两个地址的值已经

改变.即x=10;y=20;此例采用传址方式,通过被调

函数参数的改变,影响主调参数。

,Bdck4

/露第8章指针_____________________________

【例8.14】求一维数组中全部元素之和

intadd(int*pt,intn)

{inti,sum=O;

for(i=0;i<n;i++)

sum=sum+pt[i];

return(sum);

,Bdck4

/露第8章指针________________

main()

{inta[10]={l,2,3A5965758,9,10};

int*p,total;

p=a;

total=add(p,10);

printf(ntotal=%d\nn,total);

)

运行结果:

total=55

<Bdck<

茎0第8章指针

8.8.2数组名作为函数的参数

指针的本质是地址,而数组名代表数组的首地

址。指针可以作为参数,数组名也就可以做参数,

一维数组名作为函数形参时,数组名后面要跟着

口,口中间可以有整数常量,也可以没有,其

实一维数组参数的函数名后面的口只是一个标记,

中间的整数将被忽略。

,Bdck4

盛露第8章指针-----------------------

【例8.15】求一维数组各元素的平均值

floataverage(floatp[],intn)

{inti;

floatsum=0.0,ave;

for(i=0;i<n;i++)

sum=sum+p[i];

ave=sum/n;

return(ave);

<Bdck<

盛露第8章指针________________________

#defineN10

main()

{floatnum[N],aver;

inti;

for(i=0;i<N;i++)

scanf(n%f,,&num[i]);

aver=average(num,N)

print*"average=%8.2f\n”,aver);

<Bdck<

盛露第8章指针_________________________________

运行情况如下:

102030405060708090100/

average=55.00

程序说明:

本例中,首先定义了一个实型函数averageO,有

一个形参为实型数组名P。在函数体中,把各元素值相加

求出平均值,返回给主函数。

,Bdck4

盛露第8章指针_________________________________

实参与形参的对应关系可以有以下几种:

实参形参

数组名数组名

数组名指针变量

指针变量数组名

指针变量指针变量

,Bdck4

函露第8章指针

一维数组的地址可以作为函数参数传递,二

维数组的地址也可作函数参数传递,也可以用指

针娈量或数组名作形参以接受实参数组名传递来

的地址。在二维数组名作为函数的形参时,数组

名右边第一个[]可以为空(即使不空也会被忽

略),第二个[]中间不能为空,它是二维数组的

列数。

,Bdck4

盛露第8章指针_________________________________

二维数组指针作函数参数举例。

【例8.16】有一个班,3个学生,各学习4门课,计算总

平均分数,以及第n个学生的成绩。

main()

{voidaverage(float*p,intn);

voidsearch(float(*p)[4],intn);

floatscore[3][4]={{65,67,70,60},{80,87,90,81},

{90,99,100,98}};

average(*score,12);search(score,2);

,Bdck4

函露第8章指针

voidaverage(float*p,intn)/*定义求总平均分的函数,

形参是指针变量*/

{float*p_end;

floatsum=0,aver;

p_end=p+n-1;

fbr(;p<=p_end;p++)

sum=sum+(*p);

aver=sum/n;

prints11average=%5.2f\nn,aver);

<Bdck<

盛露第8章指针_________________________________

/*定义求第n个学生成绩的函数,形参是二维数组名*/

voidsearch(floatp[][4],intn)

{inti;

printfV'thescoresofNo,%dare:\n",n);

for(i=0;i<4;i++)

printf(n%5.2f;p[n][i]);

,Bdck4

函露第8章指针

程序运行结果如下:

average=82.25

thescoresofNO.2are:

90.0099.00100.0098.00

,Bdck4

盛露第8章指针_________________________________

8.9带参数的main函数

带参数main函数一般形式如下:

main(intargc,char*avgv[])

说明:1、main的形参名并不一定非用argc和argv不可,只是

习惯上用这两个名字。

2、argc用于统计命令行中参数的个数(包含C文件名),

argv数组各元素依次存放命令行各参数所形成字符串的首

地址。

,Bdck4

盛露第8章指针---------------------------

main函数是由系统调用的:当系统处于操作命令

状态时,以键盘输入文件名,计算机就运行这个文件

(可执行的二进制目标文件)。例如有一源文件名为

cfile.c,经过编译连接后得到的目标文件名为

cflle.exe(在TurboC情况下,执行文件的后缀为.exe)。

命令行格式:

C文件名[参数1[参数2.......参数n]]

说明:”C文件名”为所要运行的可执行文件名,口表

示这项可以省略,各参数间用空格隔开。

<Bdck<

盛露第8章指针________________________________

【例8.17]带参数main函数应用举例。

main(intargc,char*argv[])

{while(argc>l)

{++argv;

printf(n%s\nn,*argv);

-argc;

,Bdck4

函露第8章指针

如果从键盘输入的命令行为:

CfileComputerC_Language/

则输出为:

Computer

CLanguage

,Bdck4

函露第8章指针

8.10返回指针值的函数

一个函数可以带回一个整型值、字符值、实型值等,

也可以带回指针型的数据,即地址。

返回指针值的函数一般定义形式为:

类型名*函数名(参数表)

例如:

int*a(intx,inty)

,Bdck4

盛露第8章指针_________________________________

【例8.18]编写一个strchr函数,它的作用是在一个

字符串中找一个指定的字符,返回该字符的地址(库函

数中有此函数,今要求自己编写)。

char*strchr(char*str,charch)

{while(*str++!='\O')if(*str==ch)return(str);

return(0);

<Bdck<

盛露第8章指针_________________________________

main()

{char*pt,ch,line[]=nIloveChina";

ch—c1;

pt=strchr(line,ch);

printf("\nstringstartsataddress%o.\n"Jine);

printf("Firstoccurrenceofchar%cisaddress%o.\n".ch,pt);

printf("Thisisposition%d(staringfrom0)\n”,pt-line);

<Bdck<

遍露第8章指针

运行结果如下:

stringstartsasaddress177720

FirstoccurrenceofcharCisaddress177727

Thisisposition7(startingfrom0)。

返回指针的函数是很有用的,许多库函数都

是返回指针值的。读者应很好地掌握它。

,Bdck4

函露第8章指针

8.11函数指针的定义与引用

8.11.1函数指针的定义

可以用指针变量指向整型变量、字符串、数组、也可

以指向一个函数。一个函数在编译时被分配给一个入口

地址,这个入口地址就称为函数的指针,即函数指针。

函数指针变量定义的一般形式:

数据类型标识符(*指针变量名)()

,Bdck4

盛露第8章指针_________________________________

例如:

int(*p)()

指向整型函数的指针变量。注意*p两侧的括号不能

省略,否则成了“返回指针值的函数”To

,Bdck4

盛露第8章指针_________________________________

8.11.2函数指针变量的赋值

与数组名代表数组的起始地址一样,函数名代

表函数的入口地址。

其格式为:函数指针变量二函数名;

例如:p=max;

假设已定义了一个函数max,则上述赋值语句的

作用是将max函数的入口地址赋给指针变量p。即

使p指向函数max。注意函数名后不能带括号和参

数。

<Bdck<

盛露第8章指针_________________________________

8.11.3函数指针变量的引用

函数指针变量的引用格式为:

(*函数指针变量)(实参表列);

例如:若p指向了函数max,则(*p)(a,b)就相当于max(a,b)。

即用实参a,b调用函数max。

注意:对指向函数的指针变量P,象p+n,p++,p-等

运算是无意义的。

,Bdck4

函露第8章指针

8.11.4函数指针变量作为函数的参数

函数指针变量常用的用途之一是把指针作为

参数传递到其它函数。这个问题是C语言应用的

一个比较深入的部分,在本书中只作简单的介绍,

以便在今后用到时不致感到困惑。进一步的理解

和掌握有待于读者今后深入的学习和提高。

,Bdck4

函露第8章指针

指向函数的指针变量作为参数,实现函数地址的传

递,也就是将函数名传给形参,其原理可以简述如下:

有一个函数(假设函数名为sub),它有两个形参

(xl和x2),定义xl和x2为指向函数的指针变量。在调用

函数sub时,实参用两个函数名fl和f2给形参传递函数地

址。这样在函数sub中就可以调用fl和f2函数了。

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论