《大学c语言程序设计基础第9章指针》由会员分享,可在线阅读,更多相关《大学c语言程序设计基础第9章指针(57页珍藏版)》请在金锄头文库上搜索。
1、第九章 指针,第9章 指 针指针是语言中广泛使用的一种数据类型。能很方便地使用数 组和字符串;并能像汇编语言一样处理内存地址,正确理解和使用指针是 掌握语言的一个重要标志。诚然,指针也是语言中最为困难的一部 分内容。 一个变量有如下几个属性:变量名变量值 变量类型(存储宽度)变量存储地址-指针变量作用域变量生存期指针其实就是变量的地址。指针也是一种数据类型,它用专门的变量“指针变量”来存放。 注意:所有的数据(常量、变量)的地址都有系统来分配,用户无法指定数据的地址,只能申请和使用地址(指针)。, 9.1 地址和指针的基本概念,一、 数据的存取:,图 9.1 用户数据区地址: 变量: 2000
2、H 00000000 变量I=300000101 2002H 00000000 变量j=600000110 2004H 00000000 变量k=900001001指针变量 3010H 00000000 P=2000H 3011H 00100000,1、 内存地址:一般把存储器中的一个字节称为一个内存单元,如整型量占2个单元,字符量占1个单元等。每个内存单元的编号称为“内存地址”。程序中的每个变量都对应着内存中的一个地址,从该地址开始的一个或多个字节用来存放该数据。 2、 内存单元的地址和内存单元的数据的区别:根据内存单元的地址就可以找到内存单元中的数据,这个地址称为内存单元的指针。内存单元的
3、指针和内存单元的数据是两个不同的概念,例如,若有三个整形变量及值分别为:int i=3,j=6,k=9 则它们在内存中的存储情况如图 9.1,对于一个内存单元来说,地址是它的位置,数据是它的内容。 在语言中,允许用一个变量来存放指针,这种变量称为指针变量。 定义指针的目的是为了通过指针去访问内存单元。 程序编译后已经没有 i、j、k 这些变量名了,而是将变量名转换成了变量的地址如:2000、2002、2004。系统通过内存地址对变量进行存取。 指针变量中不仅可以存放变量的地址,也可以是其他数据结构(如: 数组、字符串、函数)的地址。因为数组、字符串、函数都是连续存放的,所以指针变量中存放的是他
4、们的首地址。,二、内存单元的直接访问和间接访问方式 1、直接访问方式:按变量地址存取变量值的方式称为直接访问方式。如语句:printf(“%d”,i);程序编译时将变量 i 转换为2000, 执行时,找到地址2000,从 2000,2001两个字节中取出数据 3,把它输出。又例如语句:scanf(“%f”, 将整型变量i 的地址存放到变量 p中,即 p 的 值为变量 i 所对应的内存单元的起始地址2000。 现在要存取 i 的值可以这样做: 找到存放i的地址的内存单元地址(3010和3011),从中取出变量i的地址值2000, 对2000和2001单元进行存取这就称为间接访问。,3、关于“指向
5、”的含意指针变量p 的值为2000,即变量 i 的地址,这样就在p和 i 之间建立 了一种联系:通过指针变量p知道变量 i 的地址,从而可找到变量 i 的内存单元, 因此说 变量 p 指向变量i,如下图所示:为了将整数10送到变量 i 中,可以有以下两种表示方法: 将10直接送到变量i所标志的单元中, 如左下图所示。 (2) 将10送到指针变量 p 所指向的单元中, 如右下图所示。,4、指针与指针变量的概念如果一个变量专门用来存放另一个变量的地址,则称这个变量为“指 针变量”。 指针变量的值(即指针变量中存放的数据)是指针(地址)。 注意区分“指针”和“指针变量”这两个概念。 几点说明 数据所
6、需内存单元的个数是由数据类型决定的。 变量的地址是指变量所占内存单元中第1个字节的地址。 地址的值与整数是有区别的。,一、指针变量的定义 1、 指针变量的定义形式: 基类型 *变量名;定义包括三个内容:(1) 指针类型说明,即定义变量为一个指针变量;(2) 指针变量名;(3) 指针所指向的变量的数据类型。 2、 定义示例例如: int i, *p1= /* p4是指向字符变量的指针变量 */应该注意的是,一个指针变量只能指向同类型的变量,如: P3 只能指 向实型变量。,9.2 指针变量的定义与引用,3、说明 “*”只是表示定义的变量为指针变量,指针变量名中并不包含“*”; “*”是指针变量的
7、标志,不可丢掉。 (2) 一个指针变量被定义之后,它所指向对象的类型就确定了。例如:int x,y,*p;double a;p&x;不能把a的地址赋给p,即不能有 p&a。 (3)所有指针变量占用相同字节的内存单元。 (4)指针变量可以指向任何类型的对象,包括指向数组、指向别的指针变量、指向函数等。 例如,可以有下列变量说明: char (*p) 5;p指向含5个元素的一维字符数组,或理解为字符型二维数组的行指针,每行为含5个元素,p+i 指向第 i 行。int *p5; P为指针型数组,其5个元素都是指针,都指向整型数组。 int * *ip; 指向整形指针的指针int *fip( ); 函
8、数值为指针的函数-指针型函数,指向整形函数。int (*pti)( ) 指向整形函数的指针 ,,此处括号强调的是:指针,二、指针运算符 “*”(间接访问变量的值)“*” 可以得到指针变量所指向的变量的值。例如:若ip为指针变量,它指向变量 i, 则 *ip 与I 等价。int i, *ip;ip= 也等价。,三、取地址运算符“ 是错的。为什么?,例J9.1: “*”运算符和“ /* 输出x的值和指针xptr所指向的变量x的值 */运行结果为:The address of x is ffd6 The value of p is ffd6The value of x is 7.100000 The
9、 value of *p is 7.100000,四、指针变量的赋值和引用 1、指针变量的赋值 指针变量在使用之前不仅要定义而且必须赋值。未经赋值的指针变量(称为:浮动指针)不能使用,否则将造成系统混乱,甚至死机。 指针变量只能赋予变量的地址值。 例如,可以用以下两种方式给指针赋值:(1) 用指针变量初始化的方法,即:int a;int *p=p2=p1,说明: (1) 指针变量定义后,若不赋值,其值是不确定的(浮动)。 (2) 可以给指针变量赋空值(NULL),使指针变量不指向任何变量,例如:#define NULL 0int *p ip=NULL; (3) 指针的值为空(NULL)与浮动指
10、针 意义是不同的。 (4) 指针变量的值是它所指对象在内存中的地址,利用运算符“ 是错误的。 (7) 被赋值的指针变量前不能再加“*”说明符,如写为 *p=&a 也是错误的。 因为 *p 表示变量的值。,2. 指针变量的引用 说明 “,(3)指针变量中的值是可以改变的。改变他的值就是改变它的指向。如: int i,j,*p1,*p2; i=a; j=b; p1= 。如图9.9所示。,图 9.8,图 9.7,图 9.9,4)指针变量可出现在表达式中。 若有定义: int x,y,*px= 于是px指向下一个整型变量了 */,例J9-2指针与+、- 的结合 (演示) #includevoid ma
11、in() int i,j,k,m,*p= 运行结果:The value of +*p is 6The value of p is ffc8The value of p+ is ffca6,8, 指针变量的引用举例 阅读P179例L9.1 a),注意到变量a,b的值并没有改变. 阅读P179例L9.1 b),注意到变量a,b的值已经改变了。指针变量的引用方法: (1) 将变量的地址赋给指针变量(p1=&a1)。 (2) 将一个指针变量赋给另一个指针变量(p2=p1;)。 (3) 通过指针变量间接访问它所指向的变量(*p1)。,五、指针变量作为函数的参数 有两种不同的方式把实参值传递给被调函数的形
12、参: 一种是前面所讲的传递实参的值; 另一种方式就是传递实参的地址。由于被调函数接收到的值是实参的地址,所以在被调函数执行过程中 就可以引用这个地址而修改主调函数中相应实参变量的值。P182页例L9.2 用传值方式和传址方式编写一个程序,输入两个整数a、b,按大小顺序输出。 (1)按“传值”调用方式编写程序并不能达到目的。因为语言中的 “参数值传递”是“单向传递”方式。即:主调函数可 以将实参的值传递给被调函数的形参,但不能通过改变形参的值而改变 实参的值。阅读P182页程序。 (2)按“传址”调用方式编写程序能得到正确的结果。 阅读P183页程序,分析下面的程序是否能交换变量的值?例J9-3
13、 #include void swap(int *px, int *py) int *temp;*temp=*px; /*危险*/*px=*py;*py=*temp; void main( ) int a, b, *p1, *p2;printf(“nInput a, b: “);scanf(“%d,%d“, (演示),答案是否定的!因为*temp是指针变量temp所指向的变量,但temp中并无确定的地址值, 因此,对一个不确定的地址单元赋值会破坏系统的稳定性。正确的做法应象P183页的程序那样。将*px的值赋给一个整型变量,用整型变量作为临时存储空间实现*px和*py的交换。,再分析下面的程序
14、是否能交换变量的值?例J10-4 #include void swap(int *px, int *py) int *p;p=px;px=py;py=p; void main( ) int a, b, *p1, *p2;printf(“nInput a, b: “);scanf(“%d,%d“, (演示),答案也是否定的。 问题在于:被调函数中形参指针的 值是被交换了,但此地址值并不能 往回传递给实参。因此,实参指针 的值并未交换,这是因为作为“参 数值传递”是单向的。,通过以上示例可得结论:如果想通过函数调用改变主调函数实参的值,则可以采用如下做法(如:4页):(1) 在主调函数中设n个变量
15、; (2)将n个变量的地址作为实参传给被调函数的形参,此时形参和实参指 向同一变量 (3)改变形参所指向变量的值就可以改变实参变量的值; 六、关于指针变量的运算的 总结说明: 1、 赋值运算(共种): 指针变量初始化赋值: 如:int a,*p= /* 把a的地址赋予指针变量pb */,把数组的首地址赋予指向数组的指针变量,例如:int a5, *pa; pa=a;pa= /* f为函数名 */,2、数组指针的加减算术运算 对于指向数组的指针变量,可以加上或减去一个整数n。指针变量加或减一个整数n的意义是:把指针指向的当前位置(指向 某数组元素)向前或向后移动n个位置。表示从当前数组元素起向前或向后 移动 n 个数组元素。但是这并不一定是移动了 n 个字节,因为不同类型 的数组元素占用不同的字节数。 例如:int a5,*pa;pa=a; /* pa指向数组a,也是指向a0 */pa=pa+2; /* pa指向a2,即pa的值为 /*pa 指向 a3*/ 指针变量的加减运算只能对数组指针变量进行。对指向其他类型变量的指针变量作加减运算是毫无意义的。,