1 / 46

第十章 指针

第十章 指针. 10.1 指针与地址 10.2 指针与变量 10.3 指针与数组 10.4 指针与字符串 10.5 指针与函数 10.6 指针数组和指向指针的指针. 变量名 a b c. 地址 2000 2002 2004. 3. 7. A. 10.1 指针与地址. 1. 地址:内存区的每一个字节的编号。 若有: int a, b; char c; a=3; b=7; c=‘A’;. p. 2000. 3. a.

santa
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. 第十章 指针 10.1 指针与地址 10.2 指针与变量 10.3 指针与数组 10.4 指针与字符串 10.5 指针与函数 10.6 指针数组和指向指针的指针

  2. . . 变量名 a b c 地址 2000 2002 2004 . . . . 3 7 A 10.1 指针与地址 1. 地址:内存区的每一个字节的编号。 若有:int a, b; char c; a=3; b=7; c=‘A’;

  3. p 2000 3 a 2. 两种访问方式 ①直接访问:通过变量名 如:scanf(“%d”, &a); printf(“%d”, a); ②间接访问:通过一个中间变量 把变量a的地址存放在另一个变量p中,通过变量p来间接访问变量a。 3. 指针:地址的形象化称谓,用来表示指向关系。 4. 指针变量:存放地址值的变量,如p。

  4. 10.2 指针与变量 10.2.1 指针变量的定义 • 形式:基类型 *指针变量名 • 基类型:表示指针变量可存放哪一类型变量的地址。 • *:表示该变量为一指针变量。 • 如:int *p ; • 表示定义了一个指针变量p,p只能指向int型的变量,即p只能存放一个int型变量的地址值。

  5. p a 10.2.2 指针变量的引用 先定义后使用,使指针变量有一确定的指向(赋初值)。 1. 两个相关的运算符 (1)&:取地址运算符 (2)* :指针运算符,取指向。 例:int a, *p ; //此时的*并非指针运算符 p=&a ; //指针变量p指向a *p=3 ; //*p表示p所指向的量,即a &a 3

  6. 2. 注意: (1)指针变量只能存放地址,不能存放其他非地址类型的数据。 如:int a, *p; p=&a ; /*对*/ p=a ; /*错*/ (2)指针变量只能存放同一类型变量的地址。 如:int a, *p; char c; p=&a ; /*对*/ p=&c ; /*错*/

  7. 3. 直接访问和间接访问 若有定义:int a, *p; p=&a; (1)直接访问 scanf(“%d”, &a); printf(“%d”, a); (2)间接访问 scanf(“%d”, p); printf(“%d”, *p); 形式: scanf(“%d”, 指针变量名); printf(“%d”, *指针变量名);

  8. 例10.1 通过指针变量访问整型变量 main( ) {int a=10, b=20; int *p, *q; p=&a; q=&b; printf(“%d, %d\n”, a, b); printf(“%d, %d\n”, *p, *q); } 结果:10,20 10,20

  9. p p &a &a 5 8 a a q q &b &b 8 5 b b *p 例10.2 利用指针变量交换a和b的值。 ①交换整型变量的值 main( ) {int a=5, b=8; int *p, *q, t; p=&a; q=&b; t=*p; *p=*q; *q=t; printf(“%d,%d\n”, a, b); printf(“%d,%d\n”,*p, *q); } 结果:8,5 8,5 *q

  10. p &a 5 a q &b 8 b ②交换指针变量的值(地址) main( ) {int a=5, b=8; int *p, *q, *t; p=&a; q=&b; t=p; p=q; q=t; printf(“%d,%d\n”, a, b); printf(“%d,%d\n”,*p, *q); } 结果:5,8 8,5 p &b 5 a q &a 8 b

  11. 4. 进一步说明两个运算符 • 优先级:相同 • 结合性:右结合性 若有 int a, *p; p=&a; 则:&*p <=> &a <=> p *&a <=> *p <=> a • ++与* :优先级相同,右结合性 若有 int a, *p; p=&a; 则:*p++ <=> *(p++) :地址值加一 (*p)++ <=> a++ :变量值加一

  12. main函数 swap函数 a p1 p &a 5 &a b q1 q &b 8 &b a p1 p &a 8 &a b q1 q &b 5 &b 10.2.3 指针变量作为函数参数 例10.3 交换a和b的值 ①交换整型变量的值 void swap(int *p, int *q) {int t; t=*p; *p=*q; *q=t; } main( ) {int a=5, b=8; int *p1=&a, *q1=&b; swap( p1, q1 ); printf(“%d,%d\n”, a, b); }

  13. main函数 swap函数 a p1 p &a 5 &a ②交换指针变量的值 void swap(int *p, int *q) {int *t; t=p; p=q; q=t; } main( ) {int a=5, b=8; int *p1, *q1; p1=&a; q1=&b; swap( p1, q1 ); printf(“%d,%d\n”, a, b); } 结果:5,8 b q1 q &b 8 &b a p1 p &a 5 &b b q1 q &b 8 &a

  14. 结论:用指针变量作为函数参数,在被调函数的执行过程中使指针变量所指向的变量值发生变化,函数调用结束后,这些变量值的变化依然保留下来。这样,就可以在主调函数中使用这些改变了的值。因此,用指针变量作参数,可以得到多个变化了的值。结论:用指针变量作为函数参数,在被调函数的执行过程中使指针变量所指向的变量值发生变化,函数调用结束后,这些变量值的变化依然保留下来。这样,就可以在主调函数中使用这些改变了的值。因此,用指针变量作参数,可以得到多个变化了的值。

  15. 10.3 指针与数组 10.3.1 指向数组元素的指针 用法与指向变量的指针变量相同 • int a[5], *p ; p=&a[0]; 等价于 p=a ; • 也可以在定义的同时赋初值 int a[5], *p=a ; /*先定义数组,再给指针变量赋值*/

  16. 10.3.2 通过指针引用数组元素 例10.5 输出数组中的全部元素 1. 下标法 main( ) {int a[5], j; for(j=0; j<5; j++) scanf(“%d”, &a[j]); for(j=0; j<5; j++) printf(“%5d”, a[j]); }

  17. 2. 指针法 • 如*(a+j)或*(p+j),等价于a[j]。 main( ) {int a[5], j; for(j=0; j<5; j++) scanf(“%d”, &a[j]); for(j=0; j<5; j++) printf(“%5d”, *(a+j) ); } main( ) {int a[5], j,*p; for(j=0; j<5; j++) scanf(“%d”, &a[j]); for( p=a; p<a+5; p++) printf(“%5d”, *p); }

  18. 3. 说明 (1)指针变量的值可以改变,但数组首地址不能改变。 若有定义:int a[5], *p=a; 则:p++; /*对*/ a++; /*错,因为数组的首地址是一个常量*/ (2)注意指针变量的当前值

  19. p p p a[0] a[1] a[2] a[3] a[4] main( ) {int a[5], j, *p; p=a; for(j=0; j<5; j++,p++) scanf(“%d”, p); p=a; for(j=0; j<5; j++,p++) printf(“%5d”, *p); }

  20. (3)注意指针变量的运算 ① p++ :指向下一个元素 ② *p++ :先取出p所指向的元素的值,然后p指向下一个元素。 ③ (*p)++ : 将p所指向的元素的值加一

  21. 10.3.3 数组名作函数参数 四种形式: (1)形参和实参都用数组名 f (int x[ ], int n) {……} main( ) {int a[10]; … f (a, 10); … } 例10.7

  22. 实际上,能够接受并存放地址值的只能是指针变量。实际上,能够接受并存放地址值的只能是指针变量。 (2)实参用数组名,形参用指针变量。 f (int *x, int n) {……} main( ) {int a[10]; … f (a, 10); … } 将例10.7中的形参改为指针变量

  23. (3)实参和形参都用指针变量 f (int *x, int n) {……} main( ) {int a[10], *p; p=a; … f (p, 10); … } 将例10.7中的参数改为指针变量

  24. (4)实参用指针变量,形参用数组名 f (int x[ ], int n) {……} main( ) {int a[10], *p; p=a; … f (p, 10); … } • 注意:如果用指针变量作实参,必须先使指针变量有确定值,指向一个已定义的数组。

  25. 用第一种形式求解例10.8 用第二种形式求解例10.8 10.3.4 指向多维数组的指针和指针变量 通过前面的介绍,我们可以得到以下两个结论: (1)一维数组名代表数组的起始地址,是一个指针常量,指向数组的第一个元素。 (2)一维数组中任一元素的地址都可以用数组名加上一个偏移量来表示。有等价关系: a <=> &a[0], a+1 <=> &a[1], … , a+i <=> &a[i] *a <=> a[0], *(a+1) <=> a[1], … ,*(a+i) <=> a[i] 在C语言中,可以把二维数组解释为以一维数组为元素的一维数组。

  26. 二维数组元素 列指针 a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3] a[0]+1 行指针 a+1 a[1]+1 a+2 a[2]+1 1. 二维数组的地址 int a[3][4]; a a[0] *(a+0)+1 a[1] *(a+1)+1 a[2] *(a+2)+1

  27. 前加 * 前加 & 行 列 列 行 • 二维数组元素a[i][j]还可以表示为: *(a[i]+j) 和 *(*(a+i)+j)。 • 行指针:指向一维数组的指针变量,加一表示加一行,如:a、a+1、a+2 等。 • 列指针:指向二维数组元素的指针变量,加一表示加一列(元素),如:a[0]和*a、a[1]+1和*(a+1)+1、a[2]+2和*(a+2)+2 等。 • 行、列指针的互换:

  28. 2. 指向二维数组的指针变量 (1)列指针:指向数组元素的指针变量 定义:与指向变量的指针变量的定义相同。 初始化:给出一维数组名(二维数组所包含的) 。 例10.12 用列指针输出数组元素的值。 main( ) {int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}}; int *p ; for( p=a[0]; p<=a[0]+11; p++) printf(“%4d”, *p); }

  29. (2)行指针:指向由m个元素组成的一维数组的指针变量。(2)行指针:指向由m个元素组成的一维数组的指针变量。 定义:基类型 (*指针变量名)[m] ; 初始化:给出二维数组名。 例10.13 输出二维数组任一行任一列元素的值。 main( ) {int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}}; int (*p)[4], i, j; p=a; scanf(“%d,%d”, &i, &j); printf(“%d\n”, *(*(p+i)+j) ); }

  30. 10.4 指针与字符串 10.4.1 字符串的表示形式 1. 下标法 例 10.18 注意:通过数组名,以%s的格式可以对一个字符串进行整体的输入输出。而对一个数值型数组,则不能企图用数组名输出它的全部元素。 如:int a[10]; …… printf(“%d\n”, a); 是不对的,数值型数组只能逐个逐个地输出元素。

  31. 2. 指针法 (1)用字符指针指向一个字符串 如:char s[ ]=“I am happy”; char *p=s; 或 char *p= “I am happy”; 此时,系统自动为字符串常量开辟存储空间,并将字符串首地址赋给指针变量p。 例10.19

  32. 10.4.2 字符指针作函数参数 用字符指针作函数参数,将一个字符串的首地址从一个函数传递到另一个函数,在被调函数中可以改变字符串的内容,在主函数中可以得到改变了的字符串。 1. 例10.20 2. 用字符指针处理例10.20 3. 简化copy函数 (1)void copy(char *from,char *to) { while( (*to=*from) !=‘\0’) /*先赋值后判断*/ { from++; to++; } }

  33. (2)void copy(char *from,char *to) {while( (*to++=*from++) !='\0') ; } 10.4.3 字符指针变量和字符数组的区别 1. 存放内容 字符数组由多个元素组成,存放若干个字符;而字符指针变量存放的是地址。 2. 赋值方式 (1)在定义的同时 char str[ ]=“I am happy”; /*整体赋初值*/ char *s=“I am happy”;

  34. (2)在赋值语句中 char str[20]; str[0]=‘I’; str[1]=‘ ’; str[2]=‘a’; …… /*只能逐个赋值*/ char *s; s=“I am happy”; /*s存放字符串常量的首地址*/ 3. 编译时的处理方式 在编译时,为数组分配一段内存单元,要为数组元素赋值;为指针变量分配一个内存单元,要为指针变量赋一地址值,使其有确定的指向。

  35. a[0] a a b b c c \0 d \0 e a[1] d f e g f f g g \0 \0 例 main( ) {char a[2][5]={“abc”, “defg”}; char *p,*s; p=a[0]; s=a[1]; while(*p) p++; while(*s) *p++=*s++; printf(“%s\n%s\n”, a[0], a[1]); } 结果:abcdefgfg fgfg

  36. 10.5 函数和指针 10.5.1 函数的指针和指向函数的指针变量 1. 定义:数据类型 (*指针变量名) ( ) ; 2. 说明: (1)数据类型要与函数返回值的类型一致 (2)括号不可省 3. 使用: (1)只需将函数名赋给指针变量,不必写参数。 (2)通过指针变量调用函数,只需用(*指针变量)代替函数名即可。 例 求两个数中的最大值

  37. 10.5.2 返回指针值的函数 • 定义:数据类型 *函数名(参数类型1 参数名1, …) • 与函数的定义相比多了一个‘*’ • 例10.25 • 区别:int *p( ) ; int (*p)( ) ;

  38. 10.6 指针数组和指向指针的指针 10.6.1 指针数组 1. 概念P248:存放指针的数组。 2. 定义:数据类型 *数组名[常量表达式] 只比整型数组的定义多了一个‘*’ 3. 区别: int *p[4] ; int (*p)[4] ;

  39. name[0] China\0 name[1] Japan\0 name[2] USA\0 name[3] India\0 4. 使用:常用来指向若干个字符串,使字符串的处理更方便灵活。 (1)定义的同时整体初始化,赋值语句中逐个赋值。 如:char *p=“China”; char *name[4]={“China”, “Japan”, “USA”, “India”}; 将各字符串常量的首地址赋值各个指针数组元素。 例10.27

  40. 10.6.2 指向指针的指针 1. 概念:指向指针数据的指针变量,即存放另一指针型数据的地址。 2. 定义:基类型 **指针变量名 比指向变量的指针变量多了一个‘*’。 3. 使用:要将一指针数组名或二维数组名赋值给它,使用方法类似于行指针。

  41. name China\0 Japan\0 USA\0 India\0 例10.28 使用指向指针的指针。 main( ) {char *name[4]={“China”, “Japan”, “USA”, “India”}; char **p ; int j; for(j=0; j<4; j++) { p=name+j; printf(“%s\n”, *p); } }

  42. p &a[0] 1 &a[1] 3 &a[2] 5 &a[3] 7 &a[4] 9 例10.29 使用指向指针的指针 main( ) {static int a[5]={1,3,5,7,9}; int *num[5]={&a[0], &a[1], &a[2], &a[3], &a[4]}; int **p, j; p=num; for(j=0; j<5; j++) { printf(“%d ”, **p); p++; } }

  43. 10.6.3 指针数组作main函数的形参 main函数可以有形参,main函数是由系统以命令的方式调用的,实参与命令一起给出。 • 带参main函数的原型: void main(int argc, char *argv[ ]) • 说明:①argc是命令行中参数的个数(包括文件名) ②argv是一个指向字符串的指针数组 • 命令行的一般形式: 文件名 参数1 参数2 …… 参数n

  44. argv file1\0 China\0 Beijing\0 例 main(int argc, char *agrv[ ]) { while(argc>1) { argv++ ; printf(“%s\n”, *argv); argc-- ; } } 若以下输入命令: file1 China Beijing 则结果为:China Beijing

  45. 作业 (一) 作业均要求用指针方法处理 1. 习题10.1 2. 习题10.3 3. 习题10.4 4. 有一个班4个学生,5门课。要求使用列指针求出第一个学生的平均成绩,用行指针求出第一门课的平均成绩。

  46. (二) 作业均要求用指针方法处理 1. 习题10.6 2. 习题10.7 3. 写一函数,用于判断一个串是否为“回文”(顺读和逆读结果相同)。例如:“abcdcba”为回文,“abcdba”不是回文。 4. 用指向指针的指针的方法将一个字符串逆序输出。

More Related