中央电大C语言A课程辅导.docx

上传人:b****5 文档编号:4316752 上传时间:2022-11-29 格式:DOCX 页数:13 大小:22.72KB
下载 相关 举报
中央电大C语言A课程辅导.docx_第1页
第1页 / 共13页
中央电大C语言A课程辅导.docx_第2页
第2页 / 共13页
中央电大C语言A课程辅导.docx_第3页
第3页 / 共13页
中央电大C语言A课程辅导.docx_第4页
第4页 / 共13页
中央电大C语言A课程辅导.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

中央电大C语言A课程辅导.docx

《中央电大C语言A课程辅导.docx》由会员分享,可在线阅读,更多相关《中央电大C语言A课程辅导.docx(13页珍藏版)》请在冰豆网上搜索。

中央电大C语言A课程辅导.docx

中央电大C语言A课程辅导

C语言程序设计A课程辅导(5)

---第5章指针

主要内容:

一、指针的概念

二、指针变量

三、指针运算

四、指针与数组

五、动态存储分配

六、使用指针和动态存储分配的程序举例

一、指针的概念

●指针:

计算机内部存储器中一个存储(单元)字节的地址。

该地址是一个32位的二进制编码,所占有的字节数(指针类型长度)与int类型长度相同。

指针是一种特殊的数据,即不是字符和常数,而是内存单元的编码(地址)。

●指针与数据类型:

在C语言中每个指针都与一个具体的数据类型相联系,即为内存中存储该类型的一个数据的地址,具体为数据所占用存储空间(又称为存储单元或数据单元)的首字节地址。

如intx=10。

则x的地址就是一个指针,它是存储x的值10的4个存储字节的第一个字节的地址。

●指针类型:

就是它所指向的存储单元中所存数据的类型。

如一个指针指向一个整型数(即所指向的存储单元中存储的是整数),则称为整型指针;若指向一个字符,则成为字符指针。

●数据地址的表示:

在一个变量前加上&字符,就表示取该变量的地址,该地址(指针)的类型就是该数据的类型。

如intx。

&x就表示x的地址,其类型为int指针类型,可表示为int*。

●空指针:

其值为0的指针称为空指针。

空指针不指向任何数据,在stdio.h头文件中已经把NULL定义为0,所以符号常量NULL也表示为空指针。

二、指针变量

能够保存存储单元地址的变量。

一般变量保存的是字符或常数。

●定义格式:

<类型关键字>*<指针变量名>[=<指针表达式>],...。

与一般变量定义语句格式基本相同,只要在变量标识符前加上*即为指针变量。

●格式举例:

(1)intx,*p。

//定义x为int型一般变量,p为int*型指针变量

(2)inta=10,*pa=&a。

//定义int变量a并初始化10,同时定义pa为

//int*类型的指针变量,并初始化为a的地址,即整数变量的地址

(3)char*p1=0,*p2="pointer"。

//p1为空,p2指向字符串"pointer"

//把"pointer"的第1个字符的地址赋给指针变量p2,类型为char*

(4)char*d[5]={0}。

//字符数组d[5]中每个元素均为指针变量,其值为空

(5)intx=5,*px=&x,**pp=&px。

//px:

int*类型,pp:

int**类型

pppxx

&px&x5//px的地址具有int**类型

(6)char*rp[3]={"front","middle","rear"}。

//定义指针数组和初始化

(7)inta[10],*ps=a。

//数组名a的值是第1个元素的地址,

//即a[0]元素的地址&a[0],类型为int*

●输出一般指针和输出字符指针所指向的字符串:

输出一般指针时使用的格式符为"%p",输出字符指针所指向的字符串时使用的格式符为"%s"。

例如:

#include

voidmain()

{

inta=30。

char*cp。

//能够保存一个字符变量或数组元素的地址

cp="output"。

//cp指向字符串常量"output"

printf("%p%p\n",&a,cp)。

//输出指针,分别为a和'o'的地址

printf("%d%s\n",a,cp)。

//输出a的值和cp所指向的字符串

}

运行结果:

0013FF7C0042002C//十六进制8位

30output

●向字符指针输入字符串:

chara[30]。

scanf("%s",a)。

//gets(a)。

chara[30],*p=a。

scanf("%s",p)。

//gets(p)。

●利用typedef语句定义指针数据类型:

(1)typedefint*inPointer。

//定义inPointer为int*类型,

//若用inPointers1=NULL。

等价于int*s1=NULL。

(2)typedefchar*chPointer。

//定义chPointer为char*类型

(3)typedefchar*AA[10]。

//定义AA为char*[10]指针数组类型,

//若用AAaa。

等价于char*aa[10]。

三、指针运算包括赋值、取地址、间接访问、增减1等。

●赋值(=)

双目运算,把赋值号右边的指针(地址)值赋给左边的同类型的指针变量。

intx=30,*px,*py。

px=&x。

py=px。

//把x的地址赋给px,把px值赋给py,它们均指向x

●取地址(&)

单目运算,使用在一般变量的前面,表示取变量的地址。

charch='+',*p=&ch。

//取ch变量的地址赋给p,p指向ch

chars[30]="Apple",*ps=s。

//字符数组s的地址赋给ps,ps指向s,

//s和ps的值均为s数组中第1个元素'A'的存储地址

●间接访问(*)

在指针前面使用*运算符能够访问到指针所指向的对象。

如:

intx=12,*px=&x。

//px指向x,px所指向的对象x的值为12

printf("%d\n",*px+10)。

//22,使用*px+10等同于x+10

*px+=15。

//27,使用*px+=15等同于x+=15,*px即x的值变为27

●增1(++)和减1(--)

单目运算,可使用在指针变量的前面或后面,使指针变量的值增1或减1。

inta[5]={10,15,20,25,30},x,y。

int*p=a。

//p指向a[0]元素,即p的值为a[0]的地址

x=*p++。

//x的值为10,p加1后赋给p,p指向下一个元素a[1]

x=*++p。

//x的值为20,p指向元素a[2]

y=(*p)++。

//y的值为20,a[2]被加1后赋给a[2],a[2]的值变21

p--。

//运算前p指向a[2],运算后p指向a[1]

printf("%d\n",*p--)。

//输出a[1]的值15,然后p减1后指向a[0]

p=&a[3]。

printf("%d\n",--*p)。

//*p的值25,输出减1后的a[3]的值24

注意:

当指针变量p指向数组中的一个元素时,p++或++p则使p指向其下一个元素,p—或—p则使p指向其前一个元素。

若p指向a[i],则进行p++或++p运算后,p指向a[i+1];若p指向a[i],则进行p--或--p运算后,p指向a[i-1]。

●加(+)和减(-)

双目运算,使指针向后或向前移动若干个数据位置。

intb[6]={1,3,5,7,9,11}。

int*p=b,*q=p+5。

//p指向b[0],q指向b[5],p+5等同于b+5

printf("%d\n",*(q-3))。

//输出b[2]的值5

p=b+6。

//p指向b[6]数组后面的一个数据单元,即b[5]后的位置

*--p。

//取b[5]元素的值11

●加赋值(+=)和减赋值(-=)

双目运算,左边的指针变量加上或减去右边相应的值。

chara[20]="wbcdefghi"。

char*p=a。

//p指向a[0],即字符w

p+=7。

//运算后p指向a[7],即字符h

p-=4。

//运算后p指向a[3],即字符d

*p-=3。

//运算后使a[3]的值减3,由100(d的ASCII码)变为97(a的码)

●比较(==,!

=,<,<=,>,>=)

双目运算,比较左右两个指针(地址)的大小。

数组中后面元素的指针大于前面元素的指针,即&a[i+1]>&a[i]。

inta[5]={20,15,32,48,46}。

int*p。

for(p=a。

p

p++)printf("%d",*p)。

//依次输出a中每个元素值

for(p=a+4。

p>=a。

p--)printf("%d",*p)。

//逆序输出a中每个元素值

这一讲就到这里,同学们再见!

四、指针与数组

1.指针与一维数组

●一维数组名是指向该数组第一个元素的指针常量

12

25

18

30

63

44

50

inta[7]={12,25,18,30,63,44,50}。

0123456

a

*a表示a[0]元素,*a的值即为a[0]的值。

a的值等于&a[0],类型int*。

a为指针常量,即其值不可修改,所以使用a++是错误的。

道理很简单,如果允许修改数组名的值,以后就无法访问该数组了。

●数组元素的下标和指针访问方式

a[i]等价于*(a+i),分别为下标和指针访问方式。

*a与a[0],*(a+1)与a[1]等价。

假定int*p=a+i。

则*p与a[i],*p++与a[i++]等价。

for(i=0。

i<7。

i++)printf("%5d\n",a[i])。

//下标方式

等价于:

for(i=0。

i<7。

i++)printf("%5d\n",*(a+i))。

//指针方式

等价于:

for(p=a。

p

p++)printf("%5d\n",*p)。

//指针方式

等价于:

for(p=a,i=0。

i<7。

i++)printf("%5d\n",p[i])。

//下标方式

//p初始指向数组a中第1个元素,p[i]与a[i]等价,均为*(a+i)

2.指针与二维数组

●二维数组名是指向该数组第一行元素的指针常量,其值为整个二维数组空间的首地址

intb[3][4]={{1,2,3,4},{2,4,6,8},{3,6,9,12}}。

b为指向b[0]行4个元素的指针常量,其值为&b[0],亦即&b[0][0]的值,但类型为int(*)[4],而不是int*。

b[i]为i行元素(一维数组)的数组名,b[i]的值为b[i][0]元素的地址。

它们的类型均为int*。

而&b[i]的值虽然也等于b[i][0]元素的地址,但类型为int(*)[4],因为它是该行元素的首地址。

同一维数组名一样,不允许修改二维数组名的值,如进行b++操作是错误的。

●二维数组名的值可以赋给同类型的指针变量

int(*pb)[4]=b。

//把b的值赋给同类型的指针变量pb,pb也指向此数组,

//此后pb也可以作为数组名使用,访问任何元素

pb[2][3]等价与b[2][3],值为12。

注意:

int(*pb)[4]与int(*pb)[5]不同,因为pb所指向的元素个数不同。

若int*pb[4]的则定义pb为含有4个元素的整型指针数组,而不是定义指向含有4个整型元素的数组的指针。

●二维数组元素的下标和指针访问方式

b[i][j](*(b+i))[j]或*(b[i]+j)或*(*(b+i)+j)//均等价

for(i=0。

i<3。

i++){

for(j=0。

j<4。

j++)printf("%d",b[i][j])。

//*(*(b+i)+j)

printf("\n")。

}

●使用指针和数组的程序举例

例1:

#include

voidmain(){

inta[8]={3,5,7,9,11,13,15,17}。

inti,*p=a。

//p的值为&a[0]

for(i=0。

i<8。

i++){

printf("%5d",*p++)。

//先*p,后p的值加1

if((i+1)%4==0)printf("\n")。

//输出4个元素后换行

}

}

输出结果:

3579

11131517

例2:

#include

voidmain()

{

inta[8]={46,38,72,55,24,63,50,37}。

intmax=*a,min=*a。

//a[0]的值赋给max和min

int*p。

for(p=a+1。

p

p++){//扫描整个数组

if(*p>max)max=*p。

//大放max

if(*p

//小放min

}

printf("%5d%5d\n",max,min)。

//输出最大和最小值

}

输出结果:

7224

五、动态存储分配

1.动态存储分配的概念

变量和数组在计算机内存中都有对应的存储空间,该存储空间的分配时机有两种:

一种在编译阶段,或者说在程序运行前;另一种在程序运行之中。

前者称为静态存储分配方式,后者称为动态存储分配方式。

●变量的静态存储分配方式

通过一般的变量定义语句定义的变量,采用的是静态存储分配方式。

如:

intx,y。

//x和y分别对应的4个字节的存储空间是静态分配的

inta[10]。

//数组a所需要的40个字节的存储空间是静态分配的

charb[20],*p=b。

//数组b的20个字节和指针变量p的4字节是静态分配的

doublec[M][N]={{0}}。

//数组c的M*N*8个字节的存储空间是静态分配的

●变量的动态存储分配方式

变量的动态存储分配需要调用在系统头文件stdlib.h中声明的动态存储分配函数来实现,这些函数为malloc()、calloc()和realloc()三种。

2.动态存储分配函数的原型格式和功能

●malloc()函数原型格式

void*malloc(unsignedintk)。

功能:

调用它时能够分配k个字节的存储空间,并把第1个字节的地址返回,该返回值具有void*类型,可以赋给任一具体类型的指针变量。

●calloc()函数原型格式

void*calloc(unsignedintn,unsignedintk)。

功能:

调用它时能够分配n*k个字节的存储空间,并把第1个字节的地址返回,该返回值具有void*类型,可以赋给任一具体类型的指针变量。

通常用n表示数组长度,k表示元素类型的长度。

●realloc()函数原型格式

void*realloc(void*ptr,unsignedintk)。

功能:

调用它时能够分配k个字节的存储空间,接着把ptr已经指向的动态分配的存储空间的内容复制到新分配的存储空间中,最后把新分配的存储空间的第1个字节的地址返回。

由于该返回值具有void*类型,所以能够赋给任一具体类型的指针变量,通常仍赋给ptr所对应的实参指针变量,使得通过该调用后增加或缩小动态存储空间。

3.动态存储分配的调用格式举例

(1)int*pn=malloc(sizeof(int))。

//分配一个整数存储空间由指针变量pn所指向,此动态分配的变量

//为*px,可用它保存一个整数,如:

*px=25。

*px+=30。

//其值为55

(2)double*pa=calloc(10,sizeof(double))。

//分配一个具有10个双精度元素的一维数组空间,由指针变量pa

//所指向,pa也就是该动态数组的数组名(但有区别,它是变不是常),

//通过它可以访问该数组中的任何元素。

如:

*pa=12。

把12赋给

//pa[0]元素;又如:

pa[i]

(3)pa=realloc(pa,20*sizeof(double))。

//增加pa指针所指向的存储空间的大小,由10个双精度元素变为

//20个双精度元素,同时原有的存储内容被复制过来。

(4)int**top=calloc(M+1,sizeof(int*))。

//top动态数组含有M+1个元素,每个元素能够存储一个整数的地址。

4.动态存储分配的优点

允许在程序运行过程中随时确定待使用的存储空间的大小,不必象静态分配那样需要事先确定。

一般定义一个数组时,必须确切给出数组的每一维的尺寸,如:

inta[10],b[M][N]。

//M和N必须是已经定义的符号常量

动态分配定义一个数组时,所分配的存储空间的大小可以是常量,也可以是变量。

如:

(1)inta=calloc(10,4)。

//两个参数都为常量

(2)inta=calloc(x,4)。

//第1个参数为变量,分配x个整数元素的空间

(3)charb=malloc(n1+n2)。

//n1和n2为变量,分配n1+n2个字节的空间

(4)charc=malloc(sizeof(d))。

//根据另一个对象d的大小分配空间

5.动态存储空间的释放

释放动态存储空间的free()函数的原型格式

voidfree(void*ptr)。

功能:

调用它时能够把指针变量ptr所指向的动态存储空间释放掉,即归还给操作系统。

free()函数原型声明也包含在stdlib.h系统头文件中

当动态存储空间保存的内容不再使用时,可调用该free()函数及时释放掉,若没有调用它,则一直到程序运行结束时该动态存储空间才被自动释放给操作系统。

对于一般静态分配的变量,其占有的存储空间只能由C语言系统在运行时自动释放,其时机为所在的模块(复合语句)刚执行完毕。

下面看一个程序例子

#include//支持调用标准输入和输出操作的函数

#include//支持调用动态存储分配和释放函数

voidmain()

{

int*a=calloc(10,sizeof(int))。

//动态分配得到a[10]数组,

//为40字节的存储空间,同时静态分配得到a指针变量,4字节

inti。

//静态分配得到i整数变量,4字节

for(i=0。

i<10。

i++)a[i]=i*i。

//给a数组中每个元素赋值

for(i=0。

i<10。

i++)printf("%d",a[i])。

//输出a中每个元素值

printf("\n")。

//输出一个换行符

free(a)。

//a[10]数组的40个字节的动态存储空间被交还给操作系统

}//此主函数执行结束时,自动把a和i各占有的4字节交还给操作系统

程序运行结果:

0149162536496481

六、使用指针和动态存储分配的程序举例

例1:

以指针方式访问数组元素的例子

#include

#include

voidmain(){

inta[5]={3,6,9,12,15}。

int*p=a。

//把数组a的首地址赋给指针变量p

inti。

for(i=0。

i<5。

i++)printf("%5d",*p++)。

//指针方式访问数组a

printf("\n")。

//换行

for(p=a+4。

p>=a。

p--)printf("%5d",*p)。

//从后向前访问数组元素

printf("\n")。

//换行

}

输出结果:

3691215

1512963

例2:

进行简单变量动态存储分配的例子

#include

#include

voidmain()

{

intx=23,y=40,z。

int*p1=malloc(sizeof(int))。

//为*p1动态分配4字节存储空间

int*p2=malloc(sizeof(int))。

//为*p2动态分配4字节存储空间

*p1=x。

*p2=y。

//分别把x值23和y值40赋给动态变量*p1和*p2

printf("%d%d\n",*p1,*p2)。

//输出*p1和*p2的值为2340

z=*p1。

*p1=*p2。

*p2=z。

//交换*p1和*p2所保存的值

printf("%d%d\n",*p1,*p2)。

//输出*p1和*p2的值为4023

free(p1)。

free(p2)。

//释放p1和p2各自所指向的动态存储空间

}

程序运行结果:

2340

4023

例3:

动态存储分配任意大小的一维数组的例子

#include

#include

voidmain()

{

intn,i,sum=0。

int*a。

printf("从键盘给n输入一个正整数(1-10):

")。

while

(1){scanf("%d",&n)。

//输入1-10之间的数到n中

if(n>=1&&n<=10)break。

elseprintf("重输:

")。

}

a=calloc(n,sizeof(int))。

//动态分配a[n]数组空间,n是变量

a[0]=0。

a[1]=1。

//给a数组的前2个元素赋值

for(i=2。

i

i++)a[i]=a[i-1]+a[i-2]。

//从元素a[2]起,每个元素值等于前2个元素值之和

//0+1=1,1+1=2,1+2=3,2+3=5,…

for(i=0。

i

i++){

sum+=a[i]。

//计算出n个元素之和

printf("%5d",a[i])。

//依次输出每个元素值

}

printf("\nsum=%5d\n",sum)。

//输出sum的提示信息和值

free(a)。

}

程序运行结果:

从键盘给n输入一个正整数(1-10):

12

重输:

8

011235813

sum=33

例4:

动态存储分配二维数组的例子。

#include

#include

voidmain()

{

inti,j。

introw,col。

int**ab。

//定义2阶整型指针变量ab,用它指向int*类型的数据

printf("输入一个二维表格数据的行数和列数:

")。

scanf("%d%d",&row,&col)。

//输入行、列数到row和col中

ab=calloc(row,sizeof(int*))。

//得到动态分配的一维指针数组ab[row]

for(i=0。

i

i++)//依次使ab[i]指向包含col个元素的一维数组

ab[i]=calloc(col,sizeof(int))。

printf("输入%d行*%d列的二维表格数据:

\n",row,col)。

for(i=0。

i

i++)//输入数据进入二维数组ab[row][col]中

for(j=0。

j

j++)

scanf("%d",&ab[i][j])。

//等价表示:

*(ab[i]+j)

printf("\n")。

printf("输出二维表格数据:

\n")。

for(i=0。

i

i++){//按row行和col列输出数据

for(j=0。

j

j++)

printf("%5d",ab[i][j])。

printf("\n")。

}

for(

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 数学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1