收藏 分享(赏)

指针与变量.ppt

上传人:yjrm16270 文档编号:8798008 上传时间:2019-07-12 格式:PPT 页数:36 大小:741KB
下载 相关 举报
指针与变量.ppt_第1页
第1页 / 共36页
指针与变量.ppt_第2页
第2页 / 共36页
指针与变量.ppt_第3页
第3页 / 共36页
指针与变量.ppt_第4页
第4页 / 共36页
指针与变量.ppt_第5页
第5页 / 共36页
点击查看更多>>
资源描述

1、第八章 指 针,指针 指针与变量 指针与数组 指针与函数,内存地址:计算机内存的组织方式是把所有单元顺序排列,每个单元有一个顺序编号,称单元的地址。形象化地叫指针 地址本身也是用二进制编码的,任何数据对象在它被使用的时候,都必然有一个确定的存储位置,占据着确定数目的存储单元。存储在内存的数据,最终都是根据其存储位置,通过存储单元的地址访问的。 任何变量,在其存在期间,总有一个确定的、固定的存储位置,即固定的地址。变量地址可能作为数据来操作。 指针变量是C语言提供的一种操作变量地址的机制。指针变量中保存的是其它对象的地址。通过指针变量,可以进行对有关对象的访问和处理。 【讨论】C语言操作指针变量

2、和普通变量的特点,什么是直接存取?什么是间接存取?【讨论】使用指针进行程序设计的好处,8.1 地址和指针的概念,8.2.1 指针的定义1. 定义指针变量的一般形式如下:类型名 *指针变量名1,*指针变量名2,. *指针变量名n ;2. 空指针空指针是一个特殊的指针,它的值是0,C语言中用符号常量NULL(在stdio.h中定义)表示这个空值,并保证这个值不会是任何变量的地址。空指针对任何指针类型赋值都是合法的。一个指针变量具有空指针值表示当前它没有指向任何有意义的东西。3. viod指针(void *)类型的指针叫通用指针,可以指向任何的变量,C语言允许直接把任何变量的地址作为指针赋给通用指针

3、。 当需要使用通用指针所指的数据参加运算时,需要写出类型强制转换。如通用指针gp所指空间的数据是整型数据,p是整型指针,用下式转换: p=(int *)gp;,8.2 指针的定义、使用和运算,8.2.2 指针的操作 1. 指针赋值(1) 取地址运算(一元运算符&)和指针赋值 (2) 指针变量赋值 (3) 通过标准函数获得地址值 2. 间接运算(一元运算符*) 将一元运算符*放在指针变量名前,也可以是地址前,效果是由一个指针得到被它指向的变量,可以像使用普通变量一样使用该表达式。3. 移动指针 移动指针就是对指针变量加上或减去一个整数、或通过赋值运算,使指针变量指向相邻的存储单元。因此,只有当指

4、针指向一串连续的存储单元时,指针移动才有意义。,8.2 指针的定义、使用和运算,8.2.2 指针的操作3. 移动指针对指针进行加、减运算中,数字“1”不再代表十进制数“1”,而是1个存储单元长度,整型变量存储单元长度是2个字节,整型指针移动1个存储单元就是移动2个字节,双精度变量存储单元长度是8,双精度型指针移动1个存储单元就是移动8个字节,依此类推。 程序中移动指针时,不论指针的基类型是什么,只需简单地加、减一个数而不必去管它的具体长度,系统将会根据指针的基类型自动确定位移的字节数最常用的移动操作就是加一和减一操作+、-。它们分别代表指针向地址值增大的方向移动一个存储单元和指针向地址值减少的

5、方向移动一个存储单元。 两个指向同一串连续单元的指针可以进行相减的运算,结果是两个指针之间元素的个数,可以通过赋值使两个指针指向同一个单元。,8.2 指针的定义、使用和运算,8.2.2 指针的操作4. 指针比较两个指针指向同一串连续的存储单元时,可以在关系表达式中对其进行比较,判断指针的位置关系,两个指针变量的值相等,表示它们指向同一个存储单元。还可进行是否是空指针的判断。指针基类型对指针相关操作的约束和限制:(1)基类型使指针只能指向基类型定义的一类变量。(2)限制引用操作满足基类型的约束。(范围、运算、内存表示)(3)限制指针移动操作的跨度。,8.2 指针的定义、使用和运算,8.2.3 指

6、针变量的初始化 指针变量在定义时可以用任何合法的指针(地址)值进行初始化。如果在定义指针变量时没有进行初始化,全局变量和局部静态变量将被自动地初始化为空指针(0)。局部自动变量、寄存器变量将不自动初始化,这些变量建立后的值不能确定。一定要有明确的变量关联后,才能使用这些变量。,8.2 指针的定义、使用和运算,形式:类型名 函数名(类型名 形参1,类型名 形参2) /* 头部 */ 说明部分 /* 函数体*/语句部分,8.3 函数与指针,8.3.1 指针作函数参数 若函数的形参为指针类型,调用该函数时,对应实参必须是基类型相同的地址值或已指向某个存储单元的指针变量。虽然实参和形参之间还是值传递方

7、式,但由于传递的是地址值,所以形参和实参指到了同一个存储单元,函数中,通过形参操作的存储单元,与实参所指是同一单元,因此实参的值发生了改变。利用此形式,可以把两个或两个以上的数据从被调用函数中返回到调用函数。当需要通过函数改变变量值时,使用指针作函数参数。 8.3.2 返回指针的函数 指针是变量,可以由函数返回。返回指针的函数定义方法: 类型名 *函数名(类型名 形参1,类型名 形参2) 说明部分 语句部分,8.3 函数与指针,8.3.2 返回指针的函数函数体内,return语句的表达式的值必须是地址。返回值可在任何有意义的引用处使用。 8.3.3 函数指针 函数指针提供了用指针调用函数的机制

8、(间接调用)。通过函数名得到的是函数的入口地址。函数指针变量存储的是函数的入口地址。函数指针变量的定义形式为:类型名 (*指针变量名)(参数类型表);(*p)()表示p是一个指向函数入口的指针变量,它不固定指向哪一个函数,只是定义了这样一个类型的变量,专门存放函数的入口地址,程序中可以先后指向不同的函数。,8.3 函数与指针,8.3.3 函数指针使用函数指针的步骤:(1) 定义函数指针变量。形如int *p(); (2) 函数指针变量赋值:如 p = 函数名;只需给出函数名,不必给出参数。(3) 通过函数指针调用函数:如 c = (*p)(实参); 调用由p指向的函数,返回值赋给c。 【讨论】

9、函数指针和返回指针的函数在定义形式上的差别。8.3.4 函数体内指针 函数体内的指针有可能通过与指针形参的赋值等操作,指向函数体外的存储单元,因此有可能改变调用函数环境中的值,8.3 函数与指针,C语言数组和指针的关系极其密切。通过指针访问数组元素的机制是C语言特有的。 8.4.1一维数组和指针 8.4.1.1数组名和地址关系 数组名在C语言中被处理成一个地址常量,也就是数组所占连续存储单元的起始地址,一旦定义,数组名永远是数组的首地址,在其生存期不会改变。不能给数组名重新赋值。但可以用在数组名后加一个整数的办法,依次表达数组中不同元素的地址。如 int a10; a与&a0是等价的,a1的地

10、址是a+1,可用&a1表示。对数组元素a3,可以用*(a+3)来引用,也可以用*&a3来引用。,8.4 数组和指针,8.4.1.1数组名和地址关系 例:通过数组首地址引用数组元素,输出数组中全部元素。#includemain() int i,a=1,2,3,4,5;for (i=0;i5;i+)printf(“%d “,*(a+i);通过a+i,依次指向了a数组的每一个元素。使用*(a+i)引用每一个元素的值。【讨论】 C编译对数组元素寻址的操作过程。,8.4 数组和指针,8.4.1.2 通过指针引用一维数组元素 通过指针引用一维数组元素需要一个指向数组元素的指针变量,它的基类型与数组元素的类

11、型相同。 通过指针引用数组元素是C语言提供的一种高效数组访问机制。设 p指向数组a某元素地址。则:*p = 5; 将对应数组元素赋值 5。p+1 或(p+)也是指针,指向数组下一个元素。p+5; 指向p所指元素的后第五个元素。p-1 指向p所指元素的前一元素。指针有效范围必须满足数组空间的限制,避免越界访问。这个问题与数组下标越界问题的控制同样重要。 【讨论】使用指针引用数组元素与下标法引用数组元素的比较,8.4 数组和指针,8.4.1.3 通过带下标的指针变量引用一维数组元素 C语言中,一对方括号不仅用作表示数组元素的记号,而且是一种运算符,表示要进行变址运算,在一个基地址上加上相对位移形成

12、一个新地址。 设:p指向s数组的首地址时,表示数组元素si的表达式也可以是pi。实际上,p不一定要指向s的首地址,如果p= 即p指向s2,则p+3指向s5,p3引用的数组元素是s5。 有五种表示s数组元素si的方法:(1) si (2) *(s+i) (3) *(p+i) (4) pi(5) p指向si使用*p表示si,8.4 数组和指针,8.4.1.4 指针、数组和函数 数组名作函数形参,实质上是一个相应类型的指针参数。如:int fun( int a)与int fun(int *d) 是完全等价的。从形参形式上看,传递一个数组名和一个简单变量地址的方式没有任何区别,函数中无法使用sizeo

13、f判定数组实际参数的元素个数。要在函数中知道数组元素个数(操作元素个数),应在参数中传入显式的整型值。 8.4.2多维数组和指针 8.4.2.1二维数组和地址 用于说明概念的实例定义:int a34,*p; 1. 二维数组由若干个一维数组组成。 二维数组是由一维数组为元素组成的数组。实例定义了一个二维数组a,a由3个元素组成,分别是a0、a1、a2,而a0、a1、a2中的每一个又是一个由4个元素组成的一维数组。a0的4个元素为a00、a01、a02、a03,其它依此类推。,8.4 数组和指针,8.4.2.1二维数组和地址 用于说明概念的实例定义:int a34,*p; 2. 二维数组名也是一个

14、地址常量 二维数组名同样也是一个地址常量,其值为二维数组的首元素的地址。实例中a数组是二维数组,a、(a+1)、(a+2)分别是三个数组元素a0、a1、a2的地址,因此,a0与*(a+0)等价,a1与*(a+1)等价,a2与*(a+2)等价。同时,a0、a1、a2也是三个一维数组的名字,数组名a的值与a0的值相同,只是a的基类型为一维数组(一个整行),即a+1的值与a1 的值相同,a+2的值与a2 的值相同,分别表示数组中第0、第1、第2行的首地址。二维数组名应理解为一个行指针。p=a;是不合法的,因为p和a的基类型不同。同样对二维数组名a,也不能进行赋值的运算。,8.4 数组和指针,8.4.

15、2.1二维数组和地址 用于说明概念的实例定义:int a34,*p; 3. 二维数组元素的地址二维数组元素的地址也可以通过每行的首地址来表示。a0、a1、a2是三个一维数组的名字,表示各行的首地址,a0是第0行第0个元素的地址,a0+1第0行第1个元素的地址,. a1 是第1行第0个元素的地址,a1+1第1行第1个元素的地址,. ai的移动以元素为单位。实例中,&a00可用a0+0表示,&a01可用a0+1表示 二维数组元素aij的地址可以用以下五种表达式求得:&aij ai+j *(a+i)+j&a00+4*i+j a0+4*i+j,8.4 数组和指针,8.4.2.2二维数组元素引用 1.

16、通过二维数组地址引用 二维数组anm的元素aij的引用也可以用下面五种方法:aij *(ai+j) *(*(a+i)+j)(*(a+i)j *(&a00+m*i +j)2. 通过普通指针引用可以使用一个以数组元素类型为基类型的指针,依次引用二维数组的所有元素,因为这些元素,在内存中,连续顺序存放。实例中,可以用一个int型指针,依次引用所有数组元素。移动单位是int的长度。,8.4 数组和指针,8.4.2.2二维数组元素引用 3. 通过行指针引用 设 int a32,(*ptl)2; 说明符(*ptl)2中,圆括号优先级最高,*首先与ptl结合,说明ptl是一个指针变量,再与说明符2结合,说明

17、指针变量ptl的基类型是一个包含两个int元素的数组,ptl的基类型与a的相同,ptl=a;是合法赋值,ptl+1等价于a+1,等价于a1。当ptl指向a数组开头时,可以通过下面的方法引用aij:*(ptli+j) *(*(ptl+i)+j) (*(ptl+i)j ptlijptl是一个变量,值可变,a是一个常量。,8.4 数组和指针,8.4.2.3 二维数组名作函数实参 3. 通过行指针引用实参和形参类型匹配,赋值兼容(值传递)当我们实参传递给函数的是二维数组元素的地址,要求形参指针的基类型与数组元素的类型一致。同时,应传入维数信息给函数。形如:int( int *p, int m, int

18、 n)当我们调用函数的实参是二维数组的名字,则要求函数指针为行指针,因为二维数组名的基类型是一个行,这时,函数首部可以是下面的几种形式之一:fun( int aMN) fun(int aN) fun(int (*a)N),8.4 数组和指针,8.4.3 使用指针处理字符串 8.4.3.1字符指针字符指针的定义形式为: char *变量名;1. 初始化方式使字符指针指向字符串 如:char *str= “Programming”; 它的含义有二:(1) 定义一个字符指针p;(2) 建立一个字符串常量;2. 用赋值运算使指针指向一个字符串 如:char *str;str=“string one”;

19、 与第一种初始化方法完全等价。 3. 用字符数组作字符串和用字符指针指向的字符串的区别,8.4 数组和指针,8.4.3.1字符指针 3. 用字符数组作字符串和用字符指针指向的字符串的区别 如:char *str=“Programming”;与char a=“Programming”; 区别如下: (1) str是指针变量,可多次赋值,a是数组名表示地址常量,不能赋值,且a的大小固定,预先分配存储单元。 (2) 类型、大小不同, str是指针,a是数组。它们的存储不同。 (3) a的元素可重新赋值,不能通过str间接修改字符串常量的值。后果无法预料。,8.4 数组和指针,8.4.3.2使用字符指

20、针处理字符串和字符数组 1.字符指针用于输入输出字符串输出时,输出项可以是字符串或字符数组,也可以是已指向字符串的字符指针。字符串输入时,输入项可以是字符数组,也可以是字符指针。字符指针必须已经指向确切的、足够大的存储空间,以便输入字符能放在它所指的具体单元中。 2.常规字符串处理的指针实现 8.4.4 指针数组 一个数组,其元素均为指针类型数据,称为指针数组。指针数组中每一个元素都相当于一个指针变量 。一维指针数组的定义形式为:类型名 *数组名数组长度;,8.4 数组和指针,8.4.4 指针数组 例: int *pa5; 定义一个5个整型指针为数组元素的一维数组。下图中,用它表示另一个整型数

21、组元素大小关系。,8.4 数组和指针,8.4.4 指针数组 8.4.4.1 字符指针数组表示的字符串数组 定义字符型指针数组并通过赋初值来构成字符串数组 。1字符指针数组的初始化char *days=“Sunday”, “Monday”, “Tuesday”,“Wednesday”, “Thursday”, “Friday”, “Saturday”; 2字符指针数组与二维字符数组比较 二维字符数组表示的字符串在存储上是一片连续的空间,但中间可能有很多空的存储单元,因为作为数组定义,需要指定列数为最长字符串的长度加1,而实际上各字符串长度一般并不相等。字符指针数组表示的字符串在空间上是分散的。,

22、8.4 数组和指针,8.4.4.1 字符指针数组表示的字符串数组 2字符指针数组与二维字符数组比较 例:char color16=“red”, “green”, “blue”;char *color=“red”, “green”, “blue”; 下图是它们的内存表示示意。,8.4 数组和指针,8.4.4.2 指向指针的指针 指针变量的内容是数据的地址,如果数据本身一个指针,这个指针变量就是指针的指针。定义指向指针数据的指针变量的形式如下:char *p;存储形式如下图,8.4 数组和指针,8.4.4.3 命令行参数 main函数可以有参数,指针数组的一个重要应用是作为main函数的形参。【讨

23、论】main函数的调用方法。main函数的参数,跟在调用命令后,由操作系统传递给主函数,这种机制叫命令行参数。 【讨论】 trubo C中,调试带有命令行参数的程序时,参数的设置输入方法。 1. 命令行的一般形式命令行的一般形式为:命令名 参数1 参数2 参数n命令名和各参数间用空格分隔。,8.4 数组和指针,8.4.4.3 命令行参数 2. C语言如何看待命令行C语言将命令行看作由空格分隔的若干字符串,每个字符串看作是一个命令行参数。由第一个字符串(命令本身)开始从0编号。程序执行时,每个参数被处理作字符串,在程序中按照规定方式使用它们。通过主函数的参数获取命令行参数。3. 主函数原型 主函

24、数的原型为: main( int argc, char *argv);其中,argc: 命令行上字符串总数(包括命令名本身)argv: 字符指针数组,存储命令行的每个字符串,argv0是命令名,argv1是第一个参数串,argv2是第二个参数串,.。argc,argv只是形参名称,可以是其它名称,但类型一定要正确。,8.4 数组和指针,在任何一个变量使用前,都必须完成关于存储方面的有关安排:存放位置、占据多少存储单元。这个工作叫存储分配。 【讨论】存储空间的静态分配方法 【讨论】引入动态存储管理的好处8.5.1 C语言标准动态存储管理函数 标准动态存储管理函数原型在 标准头文件中描述。1. 存

25、储分配函数malloc()void *malloc(size_t n) ;形参类型size_t: 足够大的整数。返回值类型(void *):通用指针,需要通过类型强制转化成特定的指针类型。功能:分配一块能够放下大小为n的存储块,返回指向这个块的指针,如果存储申请不能满足,返回空指针。,8.5 动态存储管理,8.5.1 C语言标准动态存储管理函数 使用动态存储分配函数应该注意以下几点:(1)空间大小计算要使用sizeof函数进行计算;(2)调用malloc函数后,一定要检查返回值;(3)结果强制转换后才能赋值使用;(4)得到的空间使用时不允许越界;2. 带初始化的存储分配函数calloc() v

26、oid calloc(size_t n, size_t size);形参类型size_t:n元素个数;size_t size:单个元素空间大小。返回值类型为(void *):通用指针,需要通过类型强制转化成特定的指针类型。功能:分配一块能够放下大小为n*size的存储块,全部内容清,返回指向这个块的指针,如果存储申请不能满足,返回空指针。,8.5 动态存储管理,8.5.1 C语言标准动态存储管理函数 3. 动态存储释放函数free() void free(void *p);功能:释放指针p所指的存储块。如果p的值为空,什么也不做。调用free(q)后,p变量的指向没有改变。但不能再使用它的值。

27、除非重新指向新的数据单元。程序中,应养成对不再使用的存储块立刻释放的习惯。避免造成存储块丢失。4. 分配调整函数realloc() void *realloc(void *p, size_t n);功能:更改前面做过的存储分配,指针p指向一个过去分配的存储块,n表示现在希望的存储块大小,如果新的要求不能满足,返回NULL,p仍指向原来的位置。新的分配要求可以满足,返回新存储块的指针,内容与原来块中一样。其余部分不进行初始化。不能再通过p指针使用原来的存储块。,8.5 动态存储管理,8.5.2 C语言标准动态存储管理函数的使用 (1) 一定要检查分配成功与否,常用下面的结构:if (p=(. *

28、)malloc(.)=NULL ) . /* 对分配不成功的处理 */(2) 分配空间的大小一定要用运算符sizeof来计算。(3) 分配成功后关于存储块的管理,系统完全不进行检查。 (4) 动态存储块的存在期,在其分配成功时开始,只有在用free语句释放才能导致其存储期的结束。,8.5 动态存储管理,使用指针时注意下面问题:(1) 间接引用数组元素的指针出界;(2) 没有定义指针变量的初值即使用指针;(3) 错误指针赋值 (4) 错误操作,8.6 指针实例,本章小结,本章主要知识点: 指针基本概念。变量的地址和变量的值,指针变量的说明,指针变量初始化,指针的内容,指针基本运算(取变量地址,取指针内容,指针移动,指针比较),变量与指针的关系。 指针与函数的关系。指针作为函数的参数在函数之间传递,通过指针改变调用函数中的变量,函数返回值为指针类型,指向函数的指针。 指针与数组的关系。数组名与地址关系,使用指针操作数组,二维数组下标与指针关系,函数之间传递数组的指针操作,数组指针与指针数组的概念及两者的区别,mian函数参数。 使用指针处理字符串。关于字符串的基本规定,字符串结束标记,使用指针操作字符串的基本算法,常用字符串库函数。,

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

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报