第五章 指针与结构Word下载.docx

上传人:b****3 文档编号:16446316 上传时间:2022-11-23 格式:DOCX 页数:31 大小:111.14KB
下载 相关 举报
第五章 指针与结构Word下载.docx_第1页
第1页 / 共31页
第五章 指针与结构Word下载.docx_第2页
第2页 / 共31页
第五章 指针与结构Word下载.docx_第3页
第3页 / 共31页
第五章 指针与结构Word下载.docx_第4页
第4页 / 共31页
第五章 指针与结构Word下载.docx_第5页
第5页 / 共31页
点击查看更多>>
下载资源
资源描述

第五章 指针与结构Word下载.docx

《第五章 指针与结构Word下载.docx》由会员分享,可在线阅读,更多相关《第五章 指针与结构Word下载.docx(31页珍藏版)》请在冰豆网上搜索。

第五章 指针与结构Word下载.docx

如果采取“间接存取”方式,要存取变量i的值,就必须先找到存放“i的地址”的变量p,从中取出i的地址(2000),然后到2000、2001字节取出i的值5,见图5-2:

图5-2间接存取

由于通过地址能找到所需要的变量单元,我们可以说,地址指向该变量单元,因此,在C语言中,将地址形象化为指针。

换句话说,一个变量的地址称之为该变量的“指针”,而指针变量是在一种专门存放其他变量在内存中的地址的特殊变量。

指针变量的值是地址。

5.1.2指针变量的定义

C语言规定所有变量必须遵循先定义后使用的规则。

指针变量定义格式是:

数据类型*指针变量名;

例如:

int*p;

/*p是指向int型变量的指针变量*/

float*q;

/*q是指向float型变量的指针变量*/

char*a,b;

/*其中a是指向char型变量的指针变量,而b是字符型一般变量*/

那么,怎样使一个指针变量指向另外一个变量呢?

可以用赋值语句使一个指针变量得到另外一个变量得地址,从而使它指向该变量。

inti;

/*定义i为整型变量*/

int*p;

/*定义p为指针变量*/

p=&

/*将变量i的地址赋值给指针变量p*/

注意在定义指针变量时,要注意两点:

✧指针变量前面的“*”表示该变量的类型为指针变量。

指针变量名是p,而不是*p,这是与定义整型或者字符型变量形式不同的。

✧在定义指针变量时必须指定基类型。

并且指针变量的类型是它指向的内存单元中存放数据的类型,而不是指针变量的值的类型。

那么既然指针变量,是用来存放地址的,为什么还要指定它的类型呢?

要知道不同数据在内存中所占的字节数是不同的(例如:

整型占2个字节,字符型占1个字节),在本章的稍后将要介绍指针的移动和指针的运算,例如“使指针移动1个位置”,那么这个1代表什么呢?

如果一个指针指向的是一个整型数据,那么“使指针移动1个位置”意味着移动2个字节,如果一个指针指向的是一个字符型数据,那么“使指针移动1个位置”意味着移动1个字节。

因此必须指定指针变量的基类型,并且一个指针变量只能指向同一类型的变量。

例如以下赋值是错误的:

floata;

/*定义a为float型变量*/

/*定义p为基类型为int的指针变量*/

a;

/*错误!

将float型变量的地址存放到指向整型变量的指针变量中,*/

【例5-1】通过指针变量访问整型变量

main()

{

inta,b;

/*定义a,b为整型变量*/

int*p1,*p2;

/*定义p1,p2为指向整型变量的指针变量*/

a=100;

/*为变量a赋值为100*/

b=10;

/*为变量b赋值为10*/

p1=&

/*将a的地址赋给p1*/

p2=&

b;

/*将b的地址赋给p2*/

printf("

%d,%d\n"

a,b);

/*输出a,b的值*/

*p1,*p2);

/*输出p1,p2所指向的变量的值*/

}

运行结果为:

100,10

5.1.3指针变量的引用

1.深入理解两个运算符:

*与&

设有定义语句:

int*p,a;

✧“*”是指针运算符。

“*p”出现在定义语句和非定义语句中的含义是不一样的!

在定义语句中,星号*声明其后的变量p为一指针(地址)变量;

在非定义语句中“*p”表示指针变量p指向的地址单元内的值。

✧“&

”是地址运算符,“&

a”表示取某一普通变量a的地址。

很显然,*(&

a)与a相当。

✧p=&

表示将a的地址赋给了指针变量p,即p与&

a指向了同一地址单元!

注意

✧“p=&

”语句形式经常用到,使用时指针变量与一般变量的类型必须一致!

例如本例中p,a均为整型变量,如果p,a的类型不一致那么就是错误的!

“p=a;

”是非法的语句,=号两边变量意义不同,左边为指针变量,右边为普通变量。

✧C规定,不能直接将一个常数赋给指针变量(除0以外,代表空指针)。

【例5-2】输入a、b两个整数,使用指针变量按大小顺序输出这两个整数。

main()

{

inta,b,*p1,*p2,*p;

scanf(″%d,%d″,p1,p2);

/*等价于语句scanf(″%d,%d″,&

a,&

b);

*/

if(*p1<

*p2)/*判断a,b整数的大小*/

{

p=p1;

p1=p2;

p2=p;

printf(″a=%d,b=%d\n″,a,b);

printf(″max=%d,min=%d\n″,*p1,*p2);

}

运行情况如下:

输入:

6,8

输出:

max=8,min=6

当输入6,8后,由于*p1<

*p2,将p1和p2交换。

交换前的情况如图5-3(a),交换后

的情况如图5-3(b)。

请注意,a和b的值并没有发生交换,它们仍然保持原值,但是p1和p2的值改变了。

p1的原值为&

a,后来变成了&

b,p2的原值为&

b,后来变成了&

a。

这样在输出*p1,*p2时,实际上时输出变量b和a的值,因此输出的结果为8,6。

该问题的解决思想是目标变量值不变,改变指针变量的指向求解。

请同学们想一想:

如何实现利用指针变量直接改变目标变量的值求解?

2.指针变量的算术、增量、关系等运算

设有定义语句:

int*p,*p1,*p2,a,n,v;

intq[10];

则:

(1)指针赋值运算规定,可将一个变量的地址赋给同类型的指针变量,但不能直接将常数赋给指针变量。

如“p=&

a;

”合法,“p=5000;

”非法。

(2)指针的加减运算

✧只有当指针变量指向数组时指针的加减运算才有意义。

✧指针的加减运算是以基类型为单位(即sizeof(类型))的。

✧p+n 

表示p+n*sizeof(指针类型),即从p算起,后边第n个数的地址。

✧p-n 

表示p-n*sizeof(指针类型),即从p算起,前边第n个数的地址。

✧指针变量可加减一个整型表达式。

如:

p1++、p2+3、p2-2。

p++,p--,++p,--p 

结果是指向下一个(或上一个)数据的地址,而不是指向下一个(或上一个)地址单元。

✧两个指针变量不能作加法运算,只有当两个指针变量指向同一数组时,进行指针变量相减才有实际意义。

当指针变量p2和p1同时指向数组q时,p2-p1结果表示两个地址之间能够存放某种类型数据的个数,当然数据类型与指针的类型须一致。

(3)当*与++、--结合时应注意其优先顺序和结合性:

三个运算符优先级相同,但结合顺序是从右向左。

 v=*p++:

等价v=*(p++),先取p指向单元值赋给普通变量v,然后p自增1指向下一数据单元。

 v=*++p:

表示p先自增指向下一数据单元,再将该单元之值赋给普通变量v。

 

v=(*p)++:

将(*p)值先赋给v,然后(*p)内容再增1。

v=++(*p):

将(*p)内容增1后赋给v。

(4)指针关系运算:

✧指向同一数组的两个指针可以进行关系运算,表明它们所指向元素的相互位置关系。

p2>

p1、p2==p1。

✧指针与一个整型数据进行比较是没有意义的。

✧不同类型指针变量之间比较是非法的。

✧零可以与任何类型指针进行==、!

=的关系运算,用于判断指针是否为空指针。

例如:

p1==0;

作用是判断指针变量p1是否为空.

5.2指针与数组

从前面知道,一个数组包含有若干元素,数组各元素都在内存中占用存储单元,它们都有相应的地址,而这些存储单元是连续的区域,数组名代表这块空间的起始地址。

而指针变量既然可以指向地址,当然也可以指向数组元素的地址。

通常人们习惯将数组的首地址存放到一个指针变量中,然后通过指针加减运算,存取数组各元素。

如定义语句

intx[]={1,2,3,4,5},*p=x;

此语句中的“*p=x”,将x数组的首地址赋给了指针变量p,显然可以在定义语句中将它替换成“*p=&

x[0]”形式。

用指针来指向数组元素,比用纯数组的方式操作数组要方便得多,因为数组名不能运算,而指针是可以运算的。

使用指针能使目标程序占内存少,运行速度快。

5.2.1指向一维数组的指针

定义一个指向数组元素的指针的方法,与以前介绍的指向变量的指针变量定义方法相同。

inta[10];

/*定义a为包含10个整型数据的数组*/

/*定义p为指向整型变量的指针变量*/

a[0];

/*把元素a[0]的地址赋给指针变量p*/

在C语言中规定数组名(不包含形参数组名,形参数组并不占有实际的内存单元)代表数组中首地址(即数组中第一个元素的地址)。

因此,下面两个语句等价:

p=a;

注意指针变量指向数组并不是指向整个数组,而是指向了数组中第一个元素。

上述“p=a;

”的作用是:

“把数组的首地址赋值给p”,而不是“把数组a各元素的值赋值给p”。

那么要通过指针引用数组元素,应该如何实现呢?

按C语言规定:

如果指针变量p已指向数组中的一个元素,那么p+1指向同一数组中的下一个元素,而不是简单的将p的值(地址)简单的加1。

例如,数组元素是float型,每个元素占4个字节,那么p+1意味着使p的值(地址)加4个字节,以使它指向下一个元素;

又例如数组元素是int型,每个元素占2个字节,那么p+1意味着使p的值(地址)加2个字节,以使它指向下一个元素。

也就是说,p+1所代表的地址实际上使p+1×

d,d代表一个数组元素所占的字节数。

根据上述,引用一个数组元素可以用两种方法:

(1)下标法,如a[0]形式;

(2)指针法,如*(a+i)或者*(p+i)。

其中a是数组名,p是指向数组元素的指针变量,初值为数组a的首地址。

例如有语句如下:

inta[10],*p;

⑴数组名是该数组的指针

✧a是数组的首地址(即a[0]的地址),是一个指针常量。

a=&

a[0],a+1=&

a[1],…,a+9=&

a[9]

✧数组元素的下标表示法:

a[0],a[1],…,a[i],…,a[9]

✧数组元素的指针表示法:

*(a+0),*(a+1),…,*(a+i),…,*(a+9)

⑵指向一维数组元素的指针变量

由于数组元素也是一个内存变量,所以此类指针变量的定义和使用与指向变量的指针变量相同。

例如有语句如下:

p=a;

/*相当于p=&

*/

此时p指向a[0],下面用p表示数组元素

✧下标表示法:

p[0],p[1],…,p[i],…,p[9]

✧指针表示法:

*(p+0),*(p+1),…,*(p+i),…,*(p+9)

提醒

用指针变量引用数组元素,必须关注其当前值。

如果指针变量p的初始值不一样,那么用p表示数组元素时,有一定的差异.

p=p+3;

此时,指针变量p指向第四个数组元素a[3],那么p[0]、*(p+0)等价于a[3],而*(p-1)、p[-1]等价于a[2];

*(p+1)、p[1]等价于a[4],依次类推.

【例5-3】输出一维数组中的所有元素。

inta[]={1,2,3,4,5},*p,i;

/*将数组a的首地址赋值给指针变量p*/

for(i=0;

i<

5;

i++)

\n%d,%d,%d,%d"

a[i],*(a+i),p[i],*(p+i));

}

程序分析与解释:

程序中的printf()函数展示了对一维数组元素的四种等价表示形式。

假如数组a的首地址是2000,那么p指向内存单元2000,则该数组在内存中存放形式及数组元素的表示形式如图5-4所示:

【例5-5】输入五个整数,使用指针变量将这五个数按从小到大排序后输出。

main()

{

inta[5],*pp,*p,*q,t;

for(p=a;

p<

a+5;

p++)/*输入5个整数,并且分别存放到数组a中*/

scanf("

%d"

p);

for(p=a;

a+4;

p++)/*使指针变量p指向数组a*/

pp=p;

for(q=p+1;

q<

q++)/*比较大小*/

if(*pp>

*q)

pp=q;

if(pp!

=p)/*如果本轮比较出的较小值不等于*p,那么交换值*/

t=*p;

*p=*pp;

*pp=t;

}

p++)

printf("

%d"

*p);

/*输出数组的值,并且每输出一个空一格*/

运行情况如下:

输入:

546512342

输出:

212345465

该问题的解决方法,采取的是在上一章所学的选择排序法来进行排序的.

5.2.2指向二维数组的指针

1.二维数组的地址

例如有定义语句:

inta[3][3];

✧二维数组名a是数组的首地址。

✧二维数组a包含三个行元素:

a[0]、a[1]、a[2]。

✧三个行元素的地址分别是:

a、a+1、a+2。

而a[0]、a[1]、a[2]也是地址量,是一维数组名,即*(a+0)、*(a+1)、*(a+2)是一维数组首个元素地址。

如图5-5:

2.二维数组元素的地址

a[0]、a[1]、a[2]是一维数组名,所以a[i]+j是数组元素的地址。

数组元素a[i][j]的地址可以表示为下列形式,&

a[i][j]、a[i]+j、*(a+i)+j

如图5-6所示:

3.二维数组元素的表示法

数组元素可用下列形式表示:

a[i][j]、*(a[i]+j)、*(*(a+i)+j)

a是二维数组,根据C的地址计算方法,a经过两次*操作才能访问到数组元素。

所以:

*a是a[0],**a才是a[0][0]。

看一看,想一想若a是二维数组名请理解下列表示方法的含义

a

a[0],*(a+0),*a,&

a[0][0]

a+1,&

a[1]

a[1]+2,*(a+1)+2,&

a[1][2]

a[0]是a[0][0]的地址,*a[0]是a[0][0]。

4.指向二维数组元素的指针变量

【例5-6】用指向数组元素的指针变量输出数组元素,请注意数组元素表示方法。

main()

{inta[3][4]={{0,1,2,3},{10,11,12,13},{20,21,22,23}},i,j,*p;

for(p=a[0],i=0;

i<

3;

i++)

{for(j=0;

j<

4;

j++)

%4d"

*(p+i*4+j));

/*元素的相对位置为i*4+j*/

\n"

);

此程序定义了一个二维数组a和一个指向整型变量的指针变量p。

并将数组首地址赋值给指针变量p,通过改变变量i,j的值,来输出数组元素的值,整个过程中,指针变量p的值没有发生改变。

5.2.3指向字符串的指针变量

C语言将字符串是作为数组对待的,与数值型数组一样,我们也可用字符型的指针变量指向字符串,然后通过指针变量来访问字符串存贮区域。

设有如下语句:

char*cp;

cp="

love”;

则cp指向字符串”love”常量的首字符’a’,如图5-7所示,程序中可通过cp来访问这一存贮区域。

1.指向字符串的指针变量的定义及初始化

【例5-7】通过初始化使指针指向一个字符串。

charstr1[]="

Goodmorning!

"

;

/*定义一个字符数组*/

char*str2="

Goodnight!

/*定义一个指向字符串的指针变量*/

%s\n"

str1);

str2);

C语言中对字符常量是按照字符数组来处理的,在内存中开辟了一个字符数组用来存放该字符串常量。

对字符指针str2进行初始化,实际上是把字符串的第一个元素的地址(即存放字符串的首地址)赋给了str2,见图5-8。

有人认为str2是一个字符串变量,认为在定义的时候把"

这几个字符赋给该字符串变量,这种认为是不对的。

定义指针变量str2部分:

char*str2="

等价于下面两行:

char*str2;

str2="

在输出时,要用:

printf(“%s\n”,str2);

%s是输出字符串格式控制符,在输出项要用字符指针变量名str2,则系统先输出指针所指向的字符,然后再自动使指针值加1,使之指向下一个字符,然后再输出一个字符,……,直到遇到字符串结束符’\0’为止。

注意,在内存中,字符串的最后都被自动加上了一个’\0’,如图5-8所示,因此在输出时能确定字符串的中止位置。

✧通过字符数组名或者字符指针变量可以输出一个字符串,而对数值型数组是不能企图用数组名输出它全部元素的,例如:

inta[3]={1,2,3};

printf(“%d”,a)

这种是错误的,数值型数组只能逐个元素输出。

✧对字符串中字符的存取,可以用下标法也可以用指针法。

【例5-8】已知字符串str,从中截取一子串。

要求该子串是从str的第m个字符开始,由n个字符组成。

【解题思路】

定义字符数组c存放子串,字符指针变量p用于复制子串,利用循环语句从字符串str截取n个字符。

考虑到几种特殊情况:

(1)m位置后的字符数有可能不足n个,所以在循环读取字符时,若读到‘\0’停止截取,利用break语句跳出循环。

(2)输入的截取位置m大于字符串的长度,则子串为空。

(3)要求输入的截取位置和字符个数均大于0,否则子串为空。

源程序如下:

main()

charc[80],*p,*str="

Thisisastring."

inti,m,n;

m,n="

%d,%d"

&

m,&

n);

if(m>

strlen(str)||n<

=0||m<

=0)

printf("

NULL\n"

else

for(p=str+m-1,i=0;

n;

i++)

if(*p)

c[i]=*p++;

else

break;

/*如读取到'

\0'

则停止循环*/

c[i]='

/*在c数组中加上子串结束标志*/

c);

5.3结构体

在前面,已经介绍过了基本数据类型的变量(如整型、字符型、浮点型变量),也介绍了一种构造类型数据——数组,其中数组中各元素属于同一种类型。

但是只有这些数据类型是不够的,有时需要将不同数据类型组合成一个有机的整体,以便引用。

这些组合在一个整体中的数据是互相联系的,例如:

一个学生的信息有学号、姓名、性别、年龄、住址、成绩等;

一本图书的信息有分类编号、书名、作者、出版社、出版日期、价格、库存量等。

那么如何描述这些类型不同的相关数据呢?

在C语言中允许用户自己指定这样一种数据结构,它是由若干个类型不同的(当然也可以相同)的数据项组合在一起,称为结构体(structure)。

构成结构体的各个数据项称为结构体成员。

它相当于其他高级语言中的“记录”。

如果要用C语言编写实用程序,结构的知识是不可缺少的!

同时,结构还是C++等后续语言的基础。

5.3.1结构体的定义与引用

1.结构体定义的一般格式

struct结构体名

数据类型1成员名1;

数据类型2成员名2;

……

数据类型n成员名n;

};

✧不要忽略了最后的分号。

✧struct为关键字;

✧结构体名是用户定义的类型标识,用作结构体类型的标志。

✧结

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

当前位置:首页 > 工程科技 > 电子电路

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

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