指针和结构体_第1页
指针和结构体_第2页
指针和结构体_第3页
指针和结构体_第4页
指针和结构体_第5页
已阅读5页,还剩31页未读 继续免费阅读

下载本文档

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

文档简介

1、复习:指针和结构体1指针指针变量的定义与引用指针的运算指针与数组指针与内存的动态分配2指针变量的定义与引用计算机将内存的每一个字节都编了号,这个编号称为内存的地址。在对内存的某个单元进行操作之前,程序必须知道这个单元的地址。2000200120022003200420053指针变量的定义与引用C语言中,指针实际上就是内存地址;但如果某个变量的值实际上就是另一个变量的地址,那么这个变量被称为指针变量。例如,已知有个int型变量a,那么如果将a的地址赋值给变量p(即p=&a;),那么p就是一个指针变量p的值是地址,也就是指针通常我们用箭头表示指向关系4指针变量的定义与引用C语言可以通过变量名来引用

2、变量的内存单元。通过变量名来引用变量的内存单元被称为直接引用。而通过内存地址来引用内存单元的做法称为间接引用。C语言要依靠指针变量来实现变量的间接引用。例如,下面定义了两个变量:int a,b;那么a=3表示将a的内存单元赋值成3,而b=a则表示将a的内存单元的值复制到b的内存单元中。变量引用:5指针变量的定义与引用指针变量的定义格式是:int a,*p;int *p1,*p2;其中:数据类型符可以是任何一种有效的数据类型标识符,是指针变量所指向的内存单元的数据类型;*号表明后面的变量名是个指针变量;变量名必须是一个合法的标识符。例如,下面的定义中,a是int型变量,p是指针变量(不是int型

3、变量),并且p所指向的单元是个int型数据:int a ; int *p; 6指针变量的定义与引用在定义指针变量时,可以对指针变量赋初值。但要注意,指针必须要指向一个有效的地址单元。所谓指向有效地址单元,即是程序员自己确切地知道指针指向何处。通常在为指针变量赋初值时,将指针指向前面定义的变量。例如,下面的定义:int a;int *p=&a;但如果象下面这样定义是错误的:int *p=&a; int a;7指针变量的定义与引用当一个指针指向一个变量时,程序就可以利用这个指针间接引用这个变量。间接引用的格式是:*指针变量。例如,char ch;char *p;p=&ch; /指向ch,见右图*p

4、=a; /相当于ch=a102000pa112000paa2000pch又如,下面的程序将输出:? int a,*p;p=&a;*p=10;a+;printf(a=%d,*p=%d,a,*p);a=11,*p=118指针变量的定义与引用*是间接引用运算符,是单目运算符,优先级与+、-的优先级相同,具有右结合性。表达式(*p)+不同于*p+。*p+中的+作用于p,而不是*p。指针变量之间也可以相互赋值,赋值时,如果=号右边的指针类型与左边的指针类型不同时,需要进行类型强制转换。例如:int a;int *p1,*p2;char *pc;p1=&a; /p1指向ap2=p1; /p2也指向了apc

5、=(char *)p1;/pc也指向了a,p1、p2和pc的值是相同的,都是变量a的地址9指针变量的定义与引用程序在利用指针间接引用内存单元时,将按照指针变量定义时所指向的数据类型来解释引用的内存单元。例如,下面的程序将输出:?unsigned int a;int *pi=&a;char *pc=(char *)&a;*pi=0 xFFFE;*pc=0;printf(%x,a);FF0010练一练1、将下面程序中的变量a改为,int *a; ,修改程序保证运行结果不变。(pointer.c)void main() int a; scanf(%d,&a); a+=33; printf(a=%dn

6、,a); 思考题1、指针是地址吗?指针有负值吗?2、指针变量占多大内存,指向long的指针是否比指向char的指针更占内存?3、可以用一行定义语句同时定义int型变量和int型指针吗?4、当一个指针p指向一个变量a时,利用p进行间接引用(*p)时,则*p的数据类型是受p的类型决定还是a的类型决定?11指针的运算指针是地址,地址是一种无符号的整数。但指针却不能象整数那样参与乘法和除法。因为指针乘以或除以一个数没有任何意义。1、指针可以参与加法运算。例如,int a;int *p=&a;/假设这时p的值是2001p+=3; /这时p的值将是2001+6=2007,而不是200412指针的运算如果指

7、针p是这样定义的:ptype *p;并且p的当前值是ADDR,那么p+n的值将是 ADDR+n*sizeof(ptype)。也就是说,p将以sizeof(ptype)为单位进行相加。例如,int *pi;char *pc;long *pl;pi=(int *)1000;pc=(char *)1000;pl=(long *)1000;pi+; pc+; pl+; 虽然指针可以参与加法运算,但将两个指针相加没有任何意义。/pi的值将是1002/pc的值将是1001/pl的值将是100413指针的运算2、指针也可以参与减法运算如果指针p是这样定义的:ptype *p;并且p的当前值是ADDR,那么p

8、-n的值将是ADDR-n*sizeof(ptype)也就是说,p将以sizeof(ptype)为单位进行相减。如果两个指针指向了同一块内存的不同地方,那么可以比较两个指针的大小,也可以通过两个指针的相减运算可以计算出两个指针间的数据单元的个数。14指针与数组指针与一维数组的关系我们可以这样定义并引用数组元素:int a10;int k;for(k=0;k10;k+) ak=k+1; /将数组a的各单元赋值成1,2,3,.,9,10for(k=0;k10;k+) *(a+k)=k+1; / *(a+k)等价于akC语言还规定:ak表示数组a的第k+1个元素。数组变量名是数组在内存中的地址,也就是

9、数组第一个元素在内存中的地址。地址也就是指针,因此,a可以看成是指向int型数据的指针,我们可以用指针的间接引用运算符和数组变量名来引用数组元素。例如,上面的程序中的for语句也可以写成:15指针与数组指针与一维数组的关系假设int型数组变量a的值是2000,也就是说,数组a的第一个单元a0的地址是2000(即是a的值)第二个单元a1的地址是2002(即a+1)以此类推,a2地址是2004(即a+2).ak的地址是a+k*2。所以,*(a+k)就是对ak的引用。既然数组名是一个指针,那么当将数组名赋值给一个真正的指针变量后,那个指针变量可以充当数组名使用,既可以使用下标来引用数组单元,又可以使

10、用指针间接引用运算符来引用数组单元。char str10;int k;for(k=0;k10;k+) strk=A+k;/也可写成:*(str+k)=A+k;char str10;int k; char *p;p=str;for(k=0;k10;k+) pk=A+k; /也可写成:*(p+k)=A+k;16练一练1、阅读下面的程序(pointer2.c),写结果:void main() int a=A,B,C; int k; int *p=a; for(k=0;k3;k+) printf(“%c”,pk); 如果将p的数据类型改为:char *p;程序运行结果将是:ABCA B17指针与内存的

11、动态分配我们现在来考虑这样一个问题:事先不知道学生的数量,编写程序先输入学生的数量,然后输入学生的成绩。从问题的性质来看,必须利用数组存放学生的成绩。但程序中要定义数组,必须事先指定数组的大小。如果指定的太小,不满足程序的要求,如果指定的太大,而学生的数量太小,则会造成内存的浪费。能否解决这个两难问题呢?C语言提供了动态分配内存的手段来解决这个问题。18指针与内存的动态分配实际上,C语言有两种分配内存的方式:一种是定义变量。当程序中定义了一个变量时,系统就自动为这个变量分配一块内存,这块内存的大小由变量的数据类型决定。象下面那样定义一个数组变量:int a10;系统就自动为这个数组分配大小为2

12、0个字节的内存块。这种内存分配方式称为静态内存分配。另一种内存分配方式是动态内存分配。动态内存分配是指在程序运行过程中,根据程序的实际需要来分配一块大小合适的内存。这块内存可以是一个数组,也可以是其它类型的数据单元。动态分配的内存需要有一个指针变量记录内存的地址。19指针与内存的动态分配要想在程序中动态分配内存,需要调用标准库函数malloc。malloc函数的原型:void *malloc(unsigned int size);malloc函数只带一个参数,这个参数的含义是要分配内存的大小(以字节为单位)。返回值是一个指向空类型(void)的指针,说明返回的指针所指向的内存块可以是任何类型。

13、如果malloc分配内存失败,则返回值是NULL(空指针)。如果要分配10个int型的数组,可以这样调用malloc函数:int *p;int k;p=(int *)malloc(10*sizeof(int);if(p!=NULL) for(k=0;k10;k+) pk=k+1;注意:malloc函数可能返回NULL,因此一定要检查分配的内存指针是否为空,如果是空指针,则不能引用这个指针,否则将造成系统崩溃。20指针与内存的动态分配动态分配的内存是可以释放的。计算机中最宝贵的资源就是内存,程序在需要时可以调用malloc函数向系统申请内存,在不再需要这块内存时就应该将内存返还给系统。如果程序只

14、申请内存,用完了却不返还,很容易将内存耗尽,使程序最终无法运行。因此,一定要坚持好借好还,再借不难的原则。释放内存的函数是free。free函数只带一个参数,这个参数就是要释放的内存指针。下面是它的原型:void free(void * block);注意:调用malloc和free函数的源程序中要包含 stdlib.h文件。21结构体复杂数据类型概述结构体22复杂数据类型概述已经学过的数据类型:整型:int,unsigned int,short int,long int实型:float,double,long double字符型:char数组:int an;指针:int *p;空类型:NUL

15、L思考:如何定义一个学生的信息,包括:姓名、性别、年龄、班级、学号、成绩?23复杂数据类型概述如何定义一个学生的信息,包括:姓名、性别、年龄、班级、学号、成绩?为了增强C语言的数据描述能力,C语言允许程序员定义自己的数据类型。这些数据类型被称为复杂数据类型。C语言允许程序员定义的数据类型主要包括结构体、共用体以及枚举类型。24结构体1、结构体类型的定义一个复杂的数据对象(比如学生信息)可能由多个数据项构成,比如学生的姓名、年龄、性别等数据项组合在一起构成了学生信息这个数据对象。这种数据对象可以用结构体类型来描述。结构体类型的定义格式是:struct 结构体类型名 数据类型名1 成员名1; 数据

16、类型名2 成员名2; . . 数据类型名n 成员名n; ; /必须以分号结尾结构体类型名必须是一个合法标识符类型定义时成员不能赋初值成员的数量、类型和顺序不限整个结构体的定义必须以分号结尾结构体类型通常在函数外定义,但也可以在函数内部定义结构体类型的作用域是从定义处到函数尾或文件尾25结构体1、结构体类型的定义下面定义的结构体类型可以用于描述学生信息:struct student_info char name20;/姓名 unsigned int age; /年龄 unsigned int gender; /性别 unsigned int class;/班级 int grade;/成绩 ;结构

17、体类型的变量所占内存的大小是它的成员所占内存大小的和。对于struct student_info来说,sizeof(struct student_info)=sizeof(name)+sizeof(age)+sizeof(gender)+sizeof(class)+sizeof(grade).26结构体2、结构体变量的定义和引用前面介绍的仅仅是结构体类型的定义,是一种数据类型的定义,不是变量定义。结构体类型的变量的定义格式是:struct 结构体类型名 变量名;其中关键字struct必不可少,结构体类型名必须在定义变量之前定义。例如,下面定义了一个student_info类型的变量:struc

18、t student_info stu;定义这个变量时,程序将为这个变量分配大小是sizeof(struct student_info)的内存空间,并且按照结构体类型定义中成员定义的顺序为各个成员安排内存空间。27结构体2、结构体变量的定义和引用程序员也可以一次定义多个结构体类型变量,变量间用逗号分开:struct student_info stu1,stu2;定义结构体变量时可以对变量赋初值。格式:struct 结构体类型名 变量名=成员1的值,成员2的值,.,成员n的值;注意:赋初值时, 中间的数据顺序必须与结构体成员的定义顺序相一致,否则就会出现混乱。 gender grade struc

19、t student_info stu=“Yang”,18,1,2,89; /正确 name age classstruct student_info stu=18,“Yang”,1,2,89; /错误28结构体2、结构体变量的定义和引用也可以在定义结构体类型时直接定义变量,也可以赋初值:struct student_info char name20; /姓名 unsigned int age,gender,class;/年龄,性别,班级 int grade; /成绩 stu=“wang”,18,1,2,89;如果在定义结构体类型时直接定义变量,那么可以省略结构体类型名。例如,上面的结构体定义语

20、句可以这样写:struct char name20; /姓名 unsigned int age,gender,class;/年龄,性别,班级 int grade; /成绩 stu=“wang”,18,1,2,89;29结构体2、结构体变量的定义和引用有了结构体类型符,就可以定义结构体类型的指针了。比如:struct student_info *p;对结构体类型的变量中的各成员的引用格式有两种:(1)如果通过结构体变量来访问某成员,它的格式是:变量名.成员名(2)如果通过结构体类型的指针访问某成员,它的格式是: 指针成员名 或 (*指针).成员名其中,“.”和“”称为结构体成员引用运算符,是优先

21、级最高的运算符。它们与下标运算符和圆括号()是同一个优先级,具有左结合性。30结构体2、结构体变量的定义和引用下面是结构体变量成员引用的例子:struct student_info stu;struct student_info *pstu;pstu=&stu; /指针pstu指向strcpy(,“Zhang”);/将“Zhang”复制到stu的name成员中stu.grade=100; /对stu的成员grade赋值pstuclass=2; /对stu的成员class赋值(*pstu).gender=1; /对stu的成员gender赋值31结构体2、结构体变量的定义和引用结

22、构体变量可以做整体赋值,但只能将同类型的结构体变量相互赋值,不能像赋初值那样对结构体变量赋值,也不能对结构体变量作整体输入。例如,/赋初值struct student_info stu1,stu2=“yang”,18,1,2,89;/同类型的结构体变量相互赋值stu1=stu2; /不能对结构体变量赋值stu1=“yang”,18,1,2,89;/*错误*/不能整体输入scanf(“%s,%d,%d,%d,%d”,&stu1); /错误32结构体2、结构体变量的定义和引用结构体中的成员不能是自身类型的变量,但可以是另一个结构体类型的变量,也可以是自身类型的指针。例如,struct SA int a; float f; ;struct SB int b; struct SB sb; / 错误,不能包含自身类型的变量 struct SA

温馨提示

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

评论

0/150

提交评论