1 / 27

第 十 章

第 十 章. 指 针. 主要内容 :. 一、指针在程序中的用途 二、地址和指针的概念 三、变量的指针和指针变量 四、数组与指针 五、字符串与指针 六、 返回指针值的函数. 有效的表示复杂的数据结构 能动态分配内存 方便的使用字符串 直接处理内存地址 总之,指针的应用,使程序简洁、紧凑、高效。. 一、指针在程序中的用途. 1. 数据在内存中的存储、读取过程 例如:整型变量 i , j , k ; 在编译时为变量分配内存,内存示意图如图 1 所示. 内存地址编号. 。。。. 内存中用户数据区. 3. 6. 9.

casta
Download Presentation

第 十 章

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第 十 章 指 针

  2. 主要内容: 一、指针在程序中的用途 二、地址和指针的概念 三、变量的指针和指针变量 四、数组与指针 五、字符串与指针 六、返回指针值的函数

  3. 有效的表示复杂的数据结构 能动态分配内存 方便的使用字符串 直接处理内存地址 总之,指针的应用,使程序简洁、紧凑、高效。 一、指针在程序中的用途

  4. 1.数据在内存中的存储、读取过程 例如:整型变量 i , j , k ; 在编译时为变量分配内存,内存示意图如图 1 所示. 内存地址编号 。。。 内存中用户数据区 3 6 9 2000 变量i 。。。 2002 变量j 2004 变量k 2000 3010 变量 p 二、指针的概念 (1) 假设变量 i,j,k 被分配的 内存地址分别为2000,2002,2004 (2) 给变量赋值为 i=3; j=6; k=9; (3) 通常,在程序中通过变量名对变量 进行存取。 • 其实程序经过编译后已将变量名转换为变量的地址,对变量值的存取都是通过变量的地址进行的。 图1

  5. (1) 直接访问方式 按变量地址存取变量值的方式。 如果读取变量 i的值,直接到为变量i分配的存储单元(2000、2001字节)中取出i的值(3)即可。 访问变量的两种方式: (2) 间接访问方式 先将变量 i 的地址存放在另一个变量p中,如果读取变量 i的值,先找到变量p,从p中取出内容(2000,即变量i的起始地址),然后到2000、2001字节中取出i的值(3)。 即通过变量p访问为变量i分配的内存单元。

  6. 直接访问示意图 i i p 2000 3 3 2000 2000 表示将数值3送到变量i中,可有两种表达方法: (1)将3送到变量i所标志的单元中。即直接访问方式 (2)将3送到变量p所指向的单元(变量i)中。 即间接访问方式 间接访问示意图 注意:我们并不关心变量p的存储地址, 对 变量p的访问属于直接访问。

  7. 1.变量的指针 变量的地址称为变量的指针。 2. 指针变量 存储变量地址的变量称为指针变量,用来指向另一个变量。 3.*操作符 为了表示指针变量与它所指向的变量的之间的关系,在程序中用 * 符号表示“指向”。 P *P 2000 3 i 2000 三、 指针变量 例如,P代表指针变量,* P则表示P所指向的变量。 以下两个语句作用相同: i=3; *P=3;

  8. 4.指针变量的定义 三、 指针变量(续) 定义形式: 基类型 *指针变量名; 举例 int i , j ; int *pointer1, *pointer2; 说明 (1)指针变量名前的*,表示该变量是指针型的变量。指针变量名为pointer1,而非 *pointer1。 (2)定义指针变量时必须指明基类型。 *注:以后几张幻灯片中提到的pointer1 pointer2是基于此例的。

  9. pointer1 *pointer1 3 i 三、 指针变量 5.指针运算符 & 如何使一个指针变量指向一个变量呢? 使用取地址运算符 &,即 :pointer1=&i; pointer2=&j; 赋值语句pointer1=&i;实现将变量i的地址保存入指针变量pointer1中。如右图所示。 你能画出第二个赋值语句的示意图吗?

  10. 6.指针变量的引用 pointer1 *pointer1 3 i 三、 指针变量(续) 与指针变量有关的两个运算符:& : 取地址运算符 * :间接访问运算符 例如 i=3;pointer1=&i;printf("%d",*pointer1); 说明 (1)上例将打印出i的值。 (2)*pointer1 与普通的整型变量一样使用,但前提是pointer1 必须已经明确地指向了某整型变量,或者说指针变量中必须已经存有了某整型变量的起始地址。

  11. 例1: 输入两个整数,按先大后小输出这两个整数 三、 指针变量(续) #include <stdio.h> void main() { int *p1, *p2, *p, a, b; scanf("%d%d",&a,&b); p1=&a; p2=&b; /* 取变量的地址*/ if(a<b) { p=p1; p1=p2; p2=p; } /* 指针变量间的相互赋值*/ printf("%d%d",a,b); printf("max=%d", *p1, *p2 ); } 你能画出程序中指针处理过程的示意图吗?

  12. 7.指针变量作为函数参数 三、 指针变量(续) 函数的实参值是地址,函数的形参应定义为指针类型,此时,实参和形参之间仍然是传值方式。参见例2。 变量a,b的地址被传递 到函数的形参变量p1,p2中 #include <stdio.h> void swap(int *p1, int *p2) { int temp; temp=*p1;*p1=*p2; *p2=temp; } void main() { int a,b,*pointer1, *pointer2; scanf("%d%d",&a,&b); pointer1=&a; pointer2=&b; /* 取变量的地址*/ if(a<b) swap(pointer1,pointer2); /* 函数调用,实参为指针变量*/ printf("%d%d",a,b);/* 打印函数调用后,变量a,b的值,观察其变化*/ } 在被调函数中,通过间接访问, 改变了主调函数中实参变量的值。

  13. 1.数组的存储 四、数组与指针 例如,定义数组 int a[10]; 2000 a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] • 数组在内存中占一片连续的存储区,该存储区的大小与数组的元素类型和数组长度有关。 • 每个数组元素占用相同大小的存储空间。 • 利用数组存储区的起始地址,可以逐个获得每个数组元素的存储地址。 2002 2004 2006 2000+4*2 注:假设数组a的存储区起始地址为2000。 由上图可知,数组元素a[i]的存储地址的计算公式为: 数组a的起始地址+i×元素类型占内存的字节数 2000+9*2 图2

  14. 四、数组与指针 2.指向数组元素的指针 例如,int a[10]; int*p; 对指针变量p赋值:p=&a[0]; 则使p指向了数组的第一个元素。 C语言规定:数组名代表数组的起始地址,该地址在程序运行过程中不能修改。 即数组名a是个常量。 因此,下面对指针变量p赋值的两个语句等价: p=&a[0]; p=a; 因此定义指向数组的指针变量时,可以对其初始化:int a[10]; int*p=a; (或 int*p=&a[0]; )

  15. 四、数组与指针 3.通过指针变量引用数组元素 例如,定义:int a[10] ,*p=a; 可有如下操作: p=a; p=&a[1]; *p=10; 4.指针变量表达式和指针的算术运算符 (1) 可以对指针进行有限的算术运算,包括自增运算(++)、自减运算(--)、加上一个整数、减去一个整数,以及减去一个指针变量。 (2)指针运算的结果依赖于指针所指向的对象的大小。 指针的算术运算的规则是: 当一个指针加上或减去一个整数时,指针并非简单的加上或减去该整数值, 而是加上或减去该整数与指针指向的对象的大小的乘积。 例如:int a[10] ,*p=a; 则 p=p+1; 使指针变量的值更新为数组元素a[1]的地址,即p指向了数组元素a[1]。

  16. 四、数组与指针 例如:int a[10] ,*p=a,*q,x; 假定数组a的起始地址为2000,则下列每个操作后变量的值分别为多少? 指针的算术运算 除了用于数组外 没有什么意义 p=p+1; p的值为2002,p指向数组元素a[1]. q=p; q的值为2002, q指向数组元素a[1]. q+=2; q的值为2006, q指向数组元素a[3]. 得到: 从p到q的数组元素的个数 x=q-p; x 的值为2 p++; p的值为2004, p指向数组元素a[2]. 通过++ 运算, 让指针变量指向数组中 的下一个元素。 ++p; p的值为2006 , p指向数组元素a[3]. --p; p的值为2004, p指向数组元素a[2]. 通过 -- 运算, 让指针变量指向数组中 的上一个元素。 p--; p的值为2002, p指向数组元素a[1]. 注意:a++是错误的,为什么呢?

  17. 四、数组与指针 5.指针和数组的关系 C语言中数组与指针关系密切,它们几乎可以互换。数组名可认为是一个常量指针,指针可以完成涉及数组下标的操作。 例如:int a[10] ,*p=a; 则,p指向数组的第一个元素,可用如下的指针表达式引用数组元素a[3]*(p+3) 式中的 3 是对于指针变量p的偏移量。 当p指向数组的起始位置时,偏移量等于数组的下标。 *(p+3) 这种表示法称为“指针表示法” (或 *(a+3) ) 注意 因为*的优先级高于+,所以圆括号是必需的。 总结 至此,引用一个数组元素,可以采用如下两种方法之一: (1) 下标法: 如a[i] (2) 指针法:如 *(p+i) 或 *(a+i)

  18. 四、数组与指针 例3:输出数组中的全部元素。(采用三种方法输出数组元素的值) 1.下标法 2. 通过数组名计算数组元素的地址,找出元素的值 #include <stdio.h> void main() { int a[10] , i ; for(i=0; i<10;i++) scanf("%d",&a[i]); for(i=0; i<10;i++) printf("%d",a[i]); } #include <stdio.h> void main() { int a[10] , i ; for(i=0; i<10;i++) scanf("%d",&a[i]); for(i=0; i<10;i++) printf("%d",*(a+i)); } 3. 用指针变量指向数组元素 #include <stdio.h> void main() { int a[10] , i ,*p; for(i=0; i<10;i++) scanf("%d",&a[i]); for(p=a; p<(a+10); p++) printf("%d", *p); } (1)用下标法直观; (2)用前两种方法效率一样; C编译系统是将a[i]转换为 *(a+i)来处理的 (3)用第三种方法省时间, p++操作快。

  19. 四、数组与指针 6.用数组名作函数的参数 首先回顾第八章“函数”中介绍的数组名作函数参数的情形: #include <stdio.h> void main() { int array[10] ; ... f(array,10); ... } void f( int arr[], int n) { ... ... } 规定:如果形参数组中 元素的值发生变化, 实参数组元素的值 随之变化。 说明 (1) 实参数组名代表该数组首元素的地址。而形参是用来接收 从实参传递过来的数组首元素的地址。因此,形参应该是一个指针变量(只有指针变量才能存放地址)。 (2) 虽然函数 f 的原型为 void f( int arr[], int n) ,但编译时是将arr数组按指针变量来处理的。即: void f( int arr[], int n) 与 void f( int *arr, int n) 等价

  20. i, x p=x+m j 四、数组与指针 例4.将数组a中n个元素按相反的顺序存放。 a 数组 #include <stdio.h> void inv( int *x, int n) /* 形参为指针变量*/ { int *p, temp,*i,*j, m=(n-1)/2; i=x; j=x+n-1; p=x+m;for(;i<=p; i++,j--) { temp=*i; *i=*j; *j=temp;} return; } void main() { int i,a[10]={3,7,9,11,0,6,7,5,4,2}; for(i=0;i<10;i++) printf("%d",a[i]); inv(a , 10 ); /* 函数调用,实参为数组名*/ for(i=0;i<10;i++) printf("%d",a[i]); } a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] 图3

  21. x 四、数组与指针 例5.用选择法对10个整数按由小到大顺序排序。 #include <stdio.h> void sort( int *x, int n) /* 形参为指针变量*/ { int i,j,k,t; for(i=0;i<n-1; i++) { k=i; for(j=i+1;j<n;j++) if( *(x+j)>*(x+k)) k=j; if(k!=i) {t=*(x+i);*(x+i)=*(x+k);*(x+k)=t;} } } void main() { int *p,i,a[10]; p=a; for(i=0;i<10;i++,p++) scanf("%d",p); sort(p , 10 ); /* 函数调用,实参为指针变量*/ for(i=0, p=a;i<10;i++,p++) printf("%d",*p); } a 数组 a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] 图4

  22. 四、数组与指针 7.指针和多维数组 假设有数组定义: int a[3][4]; 多维数组元素的地址 C语言规定:(1) 二维数组的起始地址为a; (2) 此二维数组由三个行元素组成:a[0],a[1],a[2]; (3) 每个行元素又是一个一维数组,包含4个元素:a[0] 为第一行的起始地址;a[0] 可用*a表示。a[1] 为第二行的起始地址;a[1] 可用*(a+1)表示。a[2] 为第三行的起始地址;a[2] 可用*(a+2)表示。(4) 第0行第0列的元素a[0][0]的地址为: a[0] ,也可用 *a表示。第0行第1列的元素a[0][1]的地址为: a[0]+1,也可用 *a+1表示。 第0行第2列的元素a[0][2]的地址为: a[0]+2,也可用 *a+2表示。第0行第3列的元素a[0][3]的地址为: a[0]+3,也可用 *a+3表示。(5) 第0行第0列的元素a[0][0]可表示为: *(a[0]),也可用 *(*a)表示。第0行第1列的元素a[0][1]可表示为: *(a[0]+1),也可用 *(*a+1)表示。 第0行第2列的元素a[0][2]可表示为: *(a[0]+2),也可用 *(*a+2)表示。第0行第3列的元素a[0][3]可表示为: *(a[0]+3),也可用 *(*a+3)表示。(6) 第1行第3列的元素a[1][3]可表示为: *(a[1]+3),也可用 *(*(a+1)+3)表示。 把 a 看成一维数组时,按照前面给出方法 表示一维数组的元素。

  23. 五、字符串与指针 1.字符串的表示形式 在C程序中,用两种方法访问字符串:(1)用字符数组存放一个字符串。 (2)用字符指针指向一个字符串。 (1)用字符数组存放一个字符串。 (2)用字符指针指向一个字符串。 #include <stdio.h> void main() { char string[]="china!" ; printf("%s\n",string); } #include <stdio.h> void main() { char *string="china!" ; printf("%s\n",string); } 用字符串常量 初始化字符指针 用字符串常量 初始化字符数组

  24. 五、字符串与指针 2.访问字符串中的字符 例6.将字符串a复制为字符串b。 #include <stdio.h> void main() { char a[]="I love china!" ,b[20]; int i; for(i=0;*(a+i)!='\0'; i++)*(b+i)=*(a+i);*(b+i)='\0'; printf("%s\n",b); }

  25. 五、字符串与指针 3.字符串指针作函数参数 例7. 用函数调用实现字符串a复制。 #include <stdio.h>void copy_string(char *from, char *to) { for(; *from!='\0'; from++,to++) *to=*from; *to='\0'; } void main() { char a[]="I love china!" ,b[20]; int i; copy_string(a,b); printf("%s\n",b); } 此循环可改为:while((*to=*from)!='\0'){to++; from++;}

  26. 六、返回指针值的函数 指针函数的定义 一个函数可以返回一个int型、float型、char型的数据,也可以返回一个指针类型的数据。 返回指针值的函数简称为指针函数。 定义形式 函数类型 *函数名([形参表]) 举例 int *func(int x , int y ){ char *string; ... return(string);}

  27. 作 业 P258: 10.1, 10.3, 10.6

More Related