第十章 指 针

108
1 C 语语语语语语 第第第 第第 第第第 第第第第1. 第第第第第第第第 2. 第第第第第第第第第第第第第第第 3. 第第第第第第第第第第第第第第第 4. 第第第第第第第第第第第第第第第第第 5. 第第第第第第第第第第第第第第第 6. 第第第第第第第第第第第第

description

本章内容 : 1. 地址和指针的概念 2. 变量的指针和指向变量的指针变量 3. 数组的指针和指向数组的指针变量 4. 字符串的指针和指向字符串的指针变量 5. 函数的指针和指向函数的指针变量 6. 指针数组和指向指针的指针. 第十章 指 针. 概 述: 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。 利用指针变量 可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。 - PowerPoint PPT Presentation

Transcript of 第十章 指 针

Page 1: 第十章   指    针

1

C 语言程序设计 第十章 指针

第十章 指 针 本章内容:1. 地址和指针的概念2. 变量的指针和指向变量的指针变量3. 数组的指针和指向数组的指针变量4. 字符串的指针和指向字符串的指针变量5. 函数的指针和指向函数的指针变量6. 指针数组和指向指针的指针

Page 2: 第十章   指    针

2

C 语言程序设计 第十章 指针

概 述: 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。 利用指针变量可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。 指针极大地丰富了C语言的功能。 学习指针是学习C语言中最重要的一环,能否正确理解和使用指针是我们是否掌握C语言的一个标志。同时,指针也是C语言中最为困难的一部分,在学习中除了要正确理解基本概念,还必须要多编程,上机调试。只要作到这些,指针也是不难掌握的。

Page 3: 第十章   指    针

3

C 语言程序设计 第十章 指针

10.1 地址和指针的概念 在计算机中,所有的数据都是存放在存储器中的。 一般把存储器中的一个字节称为一个内存单元, 不同的数据类型所占用的内存单元数不等,如整型量占 2 个单元,字符量占 1 个单元等, 在第二章中已有详细的介绍。

为了正确地访问这些内存单元, 必须为每个内存单元编上号。 根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号也叫做地址。 既然根据内存单元的编号或地址就可以找到所需的内存单元,所以通常也把这个地址称为指针。

1 、地址:内存单元的编号,通常一个字节( 1B )一个编号。

2 、指针:内存单元的地址。

Page 4: 第十章   指    针

4

C 语言程序设计 第十章 指针变量与地址

程序中 : int i;

float k;

内存中每个字节有一个编号 ----- 地址

….

..…

...

2000

2001

2002

2005

内存0

2003

i

k

编译或函数调用时为其分配内存单元

变量是对程序中数据存储空间的抽象

Page 5: 第十章   指    针

5

C 语言程序设计 第十章 指针

3 、内存单元的指针和内存单元的内容是两个不同的概念

4 、内存数据的访问方式: ( 1 )直接访问——按变量名存取变量 ( 2 )间接访问——将变量的地址存放在另一个变量(指针变量),通过指针变量来访问。

……..

30

50

60

变量 i

变量 j

变量 k

2000

2004

2002

2000 指针变量 ip

在C语言中, 允许用一个变量来存放指针,这种变量称为指针变量。一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。

地址

Page 6: 第十章   指    针

6

C 语言程序设计 第十章 指针 直接访问与间接访问

• 直接访问:按变量地址存取变量值• 间接访问:通过存放变量地址的变量去访问变量

例 i=3; ----- 直接访问

指针变量

….

..…

...

2000

2004

2006

2005

整型变量 i10

变量 i_pointer

2001

2002

2003

2000

3

例 *i_pointer=20; ----- 间接访问

20

Page 7: 第十章   指    针

7

C 语言程序设计 第十章 指针

….

..…

...

2000

2004

2006

2005

整型变量 i10

变量 i_pointer

2001

2002

2003

指针与指针变量• 指针:一个变量的地址• 指针变量:专门存放变量地址的变量叫 ~

2000

指针

指针变量

变量的内容 变量的地址

指针变量

变量

变量地址 ( 指针 )

变量值指向 地址存入

指针变量

Page 8: 第十章   指    针

8

C 语言程序设计 第十章 指针

注意:严格地说,一个指针是一个地址, 是一个常量。而一个指针变量却可以被赋予不同的指针值,是变量。 但经常把指针变量简称为指针。 为了避免混淆,我们中约定:“ 指针”是指地址, 是常量,“ 指针变量”是指取值为地址的变量。 定义指针的目的是为了通过指针去访问内存单元。

Page 9: 第十章   指    针

9

C 语言程序设计 第十章 指针

例: int a=10;

int *pa

pa=&a10

a

&a

pa

10.2 变量的指针和指向变量的指针变量• 变量的指针——变量的地址 例: &a 为变量 a 在内存单的存放地址,也称变量 a 的指针• 指针变量——存放地址的变量•指向变量的指针变量——一个指针变量存放变量 a 的地址,则称 该指针变量为指向变量 a 的指针变量。

Page 10: 第十章   指    针

10

C 语言程序设计 第十章 指针

一、指针变量的定义: 其一般形式为: 类型说明符 * 变量名; 其中, * 表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。 例如: int *p1;

表示 p1 是一个指针变量,它的值是某个整型变量的地址。 或者说 p1 指向一个整型变量。至于 p1 究竟指向哪一个整型变量, 应由向 p1 赋予的地址来决定。

Page 11: 第十章   指    针

11

C 语言程序设计 第十章 指针

再如: static int *p2; /*p2 是指向静态整型变量的指针变量 */

float *p3; /*p3 是指向浮点变量的指针变量 */

char *p4; /*p4 是指向字符变量的指针变量 */

应该注意的是,一个指针变量只能指向同类型的变量, 如 : p3 只能指向浮点变量,不能时而指向一个浮点变量, 时而又指向一个字符变量。

Page 12: 第十章   指    针

12

C 语言程序设计 第十章 指针二、指针变量的赋值 指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予具体的值。未经赋值的指针变量不能使用, 否则将造成系统混乱,甚至死机。指针变量的赋值只能赋予地址, 决不能赋予任何其它数据,否则将引起错误。 C语言中提供了地址运算符 & 来表示变量的地址。其一般形式为: & 变量名; 例如: &a 变示变量 a 的地址, &b 表示变量 b 的地址。 变量本身必须预先说明。设有指向整型变量的指针变量 p ,如要把整型变量 a 的地址赋予 p 可以有以下两种方式: (1) 指针变量初始化的方法: int a; int *p=&a;

(2) 赋值语句的方法: int a, *p;

p=&a;

Page 13: 第十章   指    针

13

C 语言程序设计 第十章 指针 指针变量的初始化

一般形式: [ 存储类型 ] 数据类型 * 指针名 = 初始地址值;

赋给指针变量,不是赋给目标变量

例 int i; int *p=&i; 变量必须已说明过

类型应一致

例 int *p=&i; int i;

例 int i; int *p=&i; int *q=p;

用已初始化指针变量作初值例 main( ) { int i; static int *p=&i; ..............

} ()不能用 auto 变量的地址去初始化 static 型指针

Page 14: 第十章   指    针

14

C 语言程序设计 第十章 指针

例 main( ) { int i=10; int *p; *p=i; printf(“%d”,*p); }

危险!

例 main( ) { int i=10,k; int *p; p=&k; *p=i; printf(“%d”,*p); }

指针变量必须先赋值 ,再使用

….

..…

...

2000

2004

2006

2005

整型变量 i10

指针变量 p

2001

2002

2003

随机

Page 15: 第十章   指    针

15

C 语言程序设计 第十章 指针

三、指针变量的运算(引用) 指针变量可以进行某些运算,但其运算的种类是有限的。 它只能进行赋值运算和部分算术运算及关系运算。1. 指针运算符(1) 取地址运算符 &

取地址运算符 & 是单目运算符,其结合性为自右至左,其功能是取变量的地址。例: &a 即变量 a 的地址(2) 取内容运算符 *

取内容运算符 * 是单目运算符,其结合性为自右至左,用来表示指针变量所指的变量。在 * 运算符之后跟的变量必须是指针变量。 例: int a=10 , *pa=&a;

*pa a 即为变量 a 的值。

Page 16: 第十章   指    针

16

C 语言程序设计 第十章 指针 & 与 * 运算符

• 含义

含义 : 取变量的地址单目运算符优先级 : 2结合性 : 自右向左

含义 : 取指针所指向变量的内容单目运算符优先级 : 2结合性 : 自右向左

• 两者关系:互为逆运算• 理解

….

..…

...

2000

2004

2006

2005

整型变量 i10

变量 i_pointer

2001

2002

2003

2000 指针变量

i_pointer----- 指针变量,它的内容是地址量*i_pointer---- 指针的目标变量,它的内容是数据&i_pointer--- 指针变量占用内存的地址

2000 10

i_pointer *i_pointer

&i_pointer

i

i_pointer &i &(*i_pointer)i *i_pointer *(&i)i_pointer = &i = &(*i_pointer)i = *i_pointer = *(&i)

Page 17: 第十章   指    针

17

C 语言程序设计 第十章 指针

注意:指针运算符 * 和指针变量说明中的指针说明符 *

不是一回事。 在指针变量说明中,“ *” 是类型说明符,表示其后的变量是指针类型。 而表达式中出现的“ *” 则是一个运算符用以表示指针变量所指的变量。 main()

{ int a=5,*p=&a;

printf ("%d",*p);

}

表示指针变量 p 取得了整型变量 a 的地址。 本语句表示输出变量 a 的值。

等价于 : printf("%d",a);

Page 18: 第十章   指    针

18

C 语言程序设计 第十章 指针说明: 若有定义: int a, *p=&a

( 1 ) &*p 表示: p

( 2 ) *&a 表示: a

( 3 ) (*p)++ 相当于 a++

( 4 ) *p++ 相当于 * ( p++) ,即先取 p 所指向变量的值,然后,让 p 指向下一个存储单元。 ( 5 ) *++p 相当于 * ( ++p) 即先让 p 指向下一个存储单元,然后再取 p 所指向变量的值。 例: int a,b,*pa=&a,*pb=&b;

pa=pb;

*pa=*pb;

上面两个语句的含意是什么?

Page 19: 第十章   指    针

19

C 语言程序设计 第十章 指针

例 y7-1.c :利用指针输入变量的值

main(){ int a,b; int *p; p=&a; scanf("%d",p); p=&b; scanf("%d",p); printf(”a=%d, b=%d\n", a,b);}

1112

Page 20: 第十章   指    针

20

C 语言程序设计 第十章 指针

2 赋值运算 指针变量的赋值运算有以下几种形式: ①指针变量初始化赋值,前面已作介绍。 ②把一个变量的地址赋予指向相同数据类型的指针变量。例如: int a,*pa;

pa=&a; /* 把整型变量 a 的地址赋予整型指针变量 pa*/

③把一个指针变量的值赋予指向相同类型变量的另一个指针变量。如: int a,*pa=&a,*pb;

pb=pa;

把 a 的地址赋予指针变量 pb ,由于 pa,pb均为指向整型变量的指针变量,因此可以相互赋值

10

a

&a

pa

&a

pb

Page 21: 第十章   指    针

21

C 语言程序设计 第十章 指针④把数组的首地址赋予指向数组的指针变量。例如: int a[5],*pa;

pa=a; (C 语言规定数组名表示数组的首地址 )

也可写为: pa=&a[0];

数组第一个元素的地址也是整个数组的首地址,也可赋予 pa

当然也可采取初始化赋值的方法: int a[5],*pa=a;

⑤把字符串的首地址赋予指向字符类型的指针变量。 例如: char *pc;

pc="C language";

或用初始化赋值的方法写为: char *pc="C Language";

这里应说明的是并不是把整个字符串装入指针变量, 而是把存放该字符串的字符数组的首地址装入指针变量。

Page 22: 第十章   指    针

22

C 语言程序设计 第十章 指针

说明:指针变量可以赋予 0 值,则 p=0 表明 p 是空指针,它不指向任何变量;在头文件 "stdio.h" 中有: #define NULL 0 ,因此在 C 程序的常常使用 int *p=NULL;让指针变量为空指针。 对指针变量赋 0 值和不赋值是不同的。指针变量未赋值时,可以是任意值,是不能使用的。否则将造成意外错误。而指针变量赋 0 值后,则可以使用,只是它不指向具体的变量而已。

例:教材 p206main(){ int a,b,*p,*p1=&a,*p2=&b; scanf("%d%d",p1,p2); if(a<b){ p=p1; p1=p2; p2=p;} printf("\na=%d, b=%d\n\n", a,b); printf("max=%d, min=%d\n", *p1,*p2);}

[ 程序演示 ]

Page 23: 第十章   指    针

23

C 语言程序设计 第十章 指针

main(){ int a,b,*p,*p1=&a,*p2=&b; scanf("%d%d",p1,p2); if(a<b){ p=p1; p1=p2; p2=p;} printf("\na=%d, b=%d\n\n", a,b); printf("max=%d, min=%d\n", *p1,*p2);}

5

a

&a

p1

&b

p2

9

b

5

a

&a

p1

&b

p2

9

b

p

Page 24: 第十章   指    针

24

C 语言程序设计 第十章 指针

四、指针变量作为函数参数 在第八章已学过:函数的参数可以是:整型、实型、字符型等数据。 C 语言中函数的参数还可以是指针类型,其作用是用来传递一个变量的地址。例 10.3 写一交换两个变量值的函数 swap() void swap(int *x, int *y) { int temp; temp=*x; *x=*y; *y=temp; }main() { int a,b,*p,*p1=&a,*p2=&b; scanf("%d%d",p1,p2); printf("\na=%d, b=%d\n\n", a,b); swap(p1,p2); printf("\na=%d, b=%d\n\n", a,b);}

Page 25: 第十章   指    针

25

C 语言程序设计 第十章 指针

5a

&a

p1

p2

9b

&b

5a

&a

p1

x

&a

9b

&b

p2

y

&b

9a

&a

p1

x

&a

5b

&b

p2

y

&b

9a

&a

p1

p2

5b

&b

程序的执行过程

调用前

调用时 在函数 swap() 中

调用结束后

Page 26: 第十章   指    针

26

C 语言程序设计 第十章 指针

void swap(int *x, int *y) { int *temp; *temp=*x; *x=*y; *y=*temp; }

此语句不对,因指针 temp 变量没有明确指向。

若将 swap 函数写为如下:

若将 swap 函数写为如下:void swap(int x, int y) { int temp; temp=x; x=y; y=temp; }

main() { int a,b; scanf("%d%d",&a,&b); printf("\na=%d, b=%d\n\n", a,b); swap(a,b); printf("\na=%d, b=%d\n\n", a,b);}

指针变量在使用前必须赋值!

Page 27: 第十章   指    针

27

C 语言程序设计 第十章 指针

5a

9b x 5

程序的执行过程

调用前

调用时 在函数 swap() 中

调用结束后

5a

y 9

9b

x

5a

y

9b

5a

9b

5

9

Page 28: 第十章   指    针

28

C 语言程序设计 第十章 指针

10.3 数组的指针和指向数组的指针变量 概念: 一个数组是由连续的一块内存单元组成的。 C 语言规定:数组名就是这块连续内存单元的首地址(称为数组的指针)。一个数组也是由各个数组元素 (下标变量 ) 组成的。每个数组元素按其类型不同占有几个连续的内存单元。一个数组元素的首地址也是指它所占有的几个内存单元的首地址。 一个指针变量既可以指向一个数组,也可以指向一个数组元素, 可把数组名或第一个元素的地址赋予它。如要使指针变量指向第 i 号元素可以把 i 元素的首地址赋予它或把数组名加 i 赋予它。

Page 29: 第十章   指    针

29

C 语言程序设计 第十章 指针

例: int a[10];

int *p=a;

p,a,&a[0] 均指向同一单元,它们是数组 a 的首地址,也是0 号元素 a[0] 的地址。

1 a[0]

a[1]a[2]a[3]

a[9]

53

79

19

p,a,&a[0]

a[i]

p+i,a+i,&a[i]

p+1,a+1,&a[1]

p+1,a+1,&a[1] 均指向 1 号元素 a[1] 。

类推可知 p+i,a+i,&a[i] 指向 i 号元素 a[i] 。

应该说明的是 p 是指针变量,而 a,&a[i]

都是常量。在编程时应予以注意。

一、指向数组元素的指针

Page 30: 第十章   指    针

30

C 语言程序设计 第十章 指针

二、通过指针引用数组元素 引入指针变量后,就可以用两种方法来访问数组元素了。 第一种方法为下标法,即用 a[i] 形式访问数组元素。 第二种方法为指针法,即采用 *(a+i) 形式,用间接访问的方法来访问数组元素。

main(){ int a[5],i,*pa=a; for(i=0;i<5;i++) {scanf("%d”, pa); pa++; } pa=a; for(i=0;i<5;i++) { printf("a[%d]=%d\n",i,*pa); pa++; } }

main(){ int a[5],i; for(i=0;i<5;i++) scanf("%d”, &a[i]); for(i=0;i<5;i++) printf("a[%d]=%d\n",i,a[i]); }

Page 31: 第十章   指    针

31

C 语言程序设计 第十章 指针main(){ int a[5],i; for(i=0;i<5;i++) *(a+i)=i; for(i=0;i<5;i++) printf("a[%d]=%d\n",i,*(a+i));}

三种方式的比较:教材 Pg. 213 。 ( 1 )下表法比较直观,但执行效率低。 ( 2 ) a[i] 编译时转换为 *(a+i) , 计算出元素的地址。 ( 3 )使用指针变量,引用元素,因 p++ 指向下一个元素,因执行效率较高。

Page 32: 第十章   指    针

32

C 语言程序设计 第十章 指针

使用指针变量要注意的几个问题: 1 、指针变量可实现本身值的改变 例如: int a[10],*p=a

p++ 指向 a[1] 元素 可以使用下面语句来输入数组元素。 for(p=a;p<a+10;p++)

scanf("%d",p);

因使用指针变量引用数组元素时要注意指针变量当前的指向,否将出错。 2 、数组名表示数组的首地址,是个地址常量,不出现如下运算:

a++; a=&a[i]; a=p;×× ×

Page 33: 第十章   指    针

33

C 语言程序设计 第十章 指针

例 10.6 通过指针变量输入输出

a 数组的 10 个元素。

main(){ int a[10],i,*p=a; for(i=0;i<10;i++) scanf("%d", p++); printf("\n"); for(i=0;i<10;i++,p++) printf("a[%d]=%d\n",i,*p); }

1 a[0]

a[1]a[2]a[3]

53

79

a[9]

------------------

分析上述程序中存在的问题?

p

p

Page 34: 第十章   指    针

34

C 语言程序设计 第十章 指针

注意指针变量的运算: 设有定义: int a[10],*p=a;

(1) p++ 指向下一个元, p 的实际值加 sizeof(int) 2,

(2) *p++ 等价于 *(p++)

(3) *(p++) 与 *(++p) 不同

(4) (*p)++ 表示 p当前所指向的元素加 1

(5) 若: p=&a[i] 则 :

*(p--) 相当于 a[i--] *(--p) 相当于 a[--i]

*(p++) 相当于 a[i++] *(++p) 相当于 a[++i]

p-a 的值为 i

Page 35: 第十章   指    针

35

C 语言程序设计 第十章 指针

例 y7-2.c :利用指针实现将 5 个整数输入到数组 a 中,然后将 a 逆序复制到 b 中,并输出 b 中各单元的值

main(){ int a[5],b[5], i; int *pa, *pb; pa=a; printf("Input the number\n",); for(i=0;i<5;i++) scanf("%d",pa++); for(i=0;i<5;i++) printf("a[%d]=%d",i,a[i]); printf(" \n");

pa=a; pb=b+4; for(i=0;i<5;i++) *pb--=*pa++; for(i=0;i<5;i++) printf(”b[%d]=%d",i,b[i]);}

Page 36: 第十章   指    针

36

C 语言程序设计 第十章 指针

二、数组名和数组指针变量作函数参数 在第八章(函数)中曾经介绍过用数组名作函数的实参和形参的问题。在学习指针变量之后就更容易理解这个问题了。 数组名就是数组的首地址,实参向形参传送数组名实际上就是传送数组的地址, 形参得到该地址后也指向同一数组。 同样,指针变量的值也是地址,数组的指针即为数组的首地址,当然也可作为函数的参数使用。例 :

float aver(float *pa);main(){ float sco[5],av,*sp; int i; sp=sco; printf("\ninput 5 scores:\n"); for(i=0;i<5;i++) scanf("%f",&sco[i]); av=aver(sp); printf("average score is %5.2f",av);}

float aver(float *pa){ int i; float av,s=0; for(i=0;i<5;i++) s=s+*pa++; av=s/5; return av;}

Page 37: 第十章   指    针

37

C 语言程序设计 第十章 指针说明:在 C 语言中形参和实参都可使用指针变量和数组名: 1 、当形参是数组时,要求对应的实参为: 同类型的数组名或指针变量 2 、当形参是指针变量,要求对应的实参为: 同类型的指针变量或数组名

形式参数

指针变量

数组名

实参数

指针变量

数组名

①②

③④

例 10.7 将数组 a 中的元素按相反顺序存放。

Page 38: 第十章   指    针

38

C 语言程序设计 第十章 指针

void inv(int x[],int n)

{ int t,i,j,m=(n-1)/2;

for(i=0;i<=m;i++)

j=n-i-1;

t=x[i];x[i]=x[j];x[j]=t;

}

main()

{ int i,a[10];

for (i=0;i<10;i++)

scanf("%d",&a[i]);

inv(a,10);

for (i=0;i<10;i++)

printf("%d ",a[i]);

}

void inv(int x[],int n) { int t,i,j,m=(n-1)/2; for(i=0;i<=m;i++) j=n-i-1; t=x[i];x[i]=x[j];x[j]=t; } main(){ int i,a[10],p=a; for (i=0;i<10;i++) scanf("%d",p++);p=a; inv(p,10); for (i=0;i<10;i++) printf("%d ",p++);}

Page 39: 第十章   指    针

39

C 语言程序设计 第十章 指针void inv(int *x,int n) { int t,i,j,m=(n-1)/2; for(i=0;i<=m;i++) j=n-i-1; t=*(x+i); *(x+i)=*(x+j); *(x+j)=t; } main(){ int i,a[10]; for (i=0;i<10;i++) scanf("%d",&a[i]); inv(a,10); for (i=0;i<10;i++) print("%d ",a[i]);}

void inv(int *x,int n) { int t,i,j,m=(n-1)/2; for(i=0;i<=m;i++) j=n-i-1; t=*(x+i); *(x+i)=*(x+j); *(x+j)=t; } main(){ int i,a[10],p=a; for (i=0;i<10;i++) scanf("%d",p++);p=a; inv(p,10); for (i=0;i<10;i++) print("%d ",p++);}

Page 40: 第十章   指    针

40

C 语言程序设计 第十章 指针例 p.219 10.8 从 10 个数中找出最大最小值

void max_min(int a[], int n, int *maxp, int *minp){ int i; *maxp=*minp=a[0]; for(i=0; i<n; i++) { if (a[i]>*maxp ) *maxp=a[i]; if (a[i]<*minp ) *minp=a[i]; }}main(){ int i,max,min, number[10]={3,7,9,11,0,6,7,5,4,2}; max_min( ??? ); printf("\nmax=%d, min=%d \n“,max,min);}

Page 41: 第十章   指    针

41

C 语言程序设计 第十章 指针

void max_min(int a[], int n, int *maxp, int *minp){ int i; *maxp=*minp=a[0]; for(i=0; i<n; i++) { if (a[i]>*maxp ) *maxp=a[i]; if (a[i]<*minp ) *minp=a[i]; }}main(){ int i,max1,min1, number1[10]={3,7,9,11,0,6,7,5,4,2}; int max2,min2, number2[20]={3,7,9,11,0,6,7,5,4,2,43,5,34,56,23,41,31,93,23}; max_min(number1,10,max1,min1); printf("\nmax=%d, min=%d \n”,max1,min1); max_min(number2,20,max2,min2 ); printf("\nmax=%d, min=%d \n”, max2,min2);}

Page 42: 第十章   指    针

42

C 语言程序设计 第十章 指针

四、指向多维数组的指针变量(一)、多维数组地址的表示方法

若有定义: int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};

0 1 2 3

4 5 6 7

8  9 10 11

a[0]

a[1]

a[2]

a

a+2

a+1

a[0] a[0]+1a[0]+2

a[0]+3

2000

2016

2008

假设数组的首地址为: 2000

2000数组名 a 为数组的首地址

Page 43: 第十章   指    针

43

C 语言程序设计 第十章 指针

二维数组的地址表示:a 二维数组名,数组首地址, 0行首地址a[0],*(a+0),*a,&a[0][0] 第 0行第 0列元素地址a+1, &a[1] 第 1行首地址a[1],*(a+1),&a[1][0] 第 1行第 0列元素地址a+i, &a[i] 第 i行首地址a[i], *(a+i), &a[i][0] 第 i行首地址

#define PF "%d,%d,%d,%d,%d,\n"main() { int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11}; printf(PF,a,*a,a[0],&a[0],&a[0][0]); printf(PF,a+1,*(a+1),a[1],&a[1],&a[1][0]); printf(PF,a+2,*(a+2),a[2],&a[2],&a[2][0]); printf("%d,%d\n",a[1]+1,*(a+1)+1); printf("%d,%d\n",*(a[1]+1),*(*(a+1)+1)); }

Page 44: 第十章   指    针

44

C 语言程序设计 第十章 指针

表示形式 含义 地址a 二维数组名,数组首地址

a[0],*(a+0),*a 第 0 行第 0 列元素地址a+1 第 1 行首地址

a[1],*(a+1) 第 1 行第 0 列元素地址

a[1]+2,*(a+1)+2,&a[1][2] 第 1 行第 2 列元素地址

*(a[1]+2),*(*(a+1)+2),a[1][2] 第 1 行第 2 列元素值

2000

2000

2008

2008

2012

6

#define PF "%d,%d,%d,%d,%d,\n"main() { int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11}; printf(PF,a,*a,a[0],&a[0],&a[0][0]); printf(PF,a+1,*(a+1),a[1],&a[1],&a[1][0]); printf(PF,a+2,*(a+2),a[2],&a[2],&a[2][0]); printf("%d,%d\n",a[1]+1,*(a+1)+1); printf("%d,%d\n",*(a[1]+1),*(*(a+1)+1)); }

Page 45: 第十章   指    针

45

C 语言程序设计 第十章 指针

设有定义: int a[3][4],i,j;

引用二维数组元素的方法:( 1 )下标法: a[i][j]

( 2 )指针法: *(*(a+i)+j)

表示形式 含义 地址a 二维数组名,数组首地址

a[0],*(a+0),*a 第 0 行第 0 列元素地址a+1 第 1 行首地址

a[1],*(a+1) 第 1 行第 0 列元素地址

a[1]+2,*(a+1)+2,&a[1][2] 第 1 行第 2 列元素地址

*(a[1]+2),*(*(a+1)+2),a[1][2] 第 1 行第 2 列元素值

2000

2000

2008

2008

2012

6

Page 46: 第十章   指    针

46

C 语言程序设计 第十章 指针

(二)、多维数组的指针变量 1 、指向数组元素的指针变量

设有定义: int a[3][4],i,j;

int *p;

p=&a[0][0];

p 为指向数组元素的指针变量,引用二维数组元素的方法: p+1 则表示指向当前元素的下一个元素。 元素 a[i][j] 的地址表示为: p+4*i+j

a[i][j] 的值表示为: *(p+4*i+j)

如果一个 n*m 的二维数组的第 i 行 j列元素相对于首地址的增量为: i*m+j

Page 47: 第十章   指    针

47

C 语言程序设计 第十章 指针

例 10.12 用指向数组元素 输出 m

main()

{ int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};

int i,j,*p;

p=&a[0][0];

for(i=0;i<12;i++)

{if (i%4==0) printf("\n");

printf("%2d ",*p++);

}

}

Page 48: 第十章   指    针

48

C 语言程序设计 第十章 指针

例 指向二维数组元素的指针变量

main(){ static 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]+12;p++) { if((p-a[0])%4==0) printf("\n");

printf("%4d ",*p); }}

int a[3][4];

a[0][0]

a[0][1]

a[1][0]

a[1][1]

a[2][0]

a[2][1]

a[0][2]

a[0][3]

a[1][2]

a[1][3]

a[2][2]

a[2][3]

p

Page 49: 第十章   指    针

49

C 语言程序设计 第十章 指针

2 、指向由 m 个元素组成的一维数组的指针变量 因为 n×m 的二维数组 a 可分解为一维数组 a[0],a[1],.. .a[n-

1] ,而它们分别又是具有 m 个元素的一维数组。 因此可定义一个指向由 m 个元素组成的一维数组的指针变量来处理二维数组。把这个指针变量称为:行指针变量 行指针变量说明的一般形式为:

类型说明符 (* 指针变量名 )[长度 ]

例: int (*p)[4] 它表示 p 是一个指针变量,它指向由 4 个元素组成的一维数组,或说 p 可指向一个有 4列的二维数组。

Page 50: 第十章   指    针

50

C 语言程序设计 第十章 指针– 指向一维数组的指针变量

» 定义形式: 数据类型 (* 指针名 )[ 一维数组维数 ];

例 int (*p)[4];

( ) 不能少int (*p)[4] 与 int *p[4] 不同

p 的值是一维数组的首地址, p是行指针

» 可让 p 指向二维数组某一行 如 int a[3][4], (*p)[4]=a;

int a[3][4];

a[0][0]

a[0][1]

a[1][0]

a[1][1]

a[2][0]

a[2][1]

a[0][2]

a[0][3]

a[1][2]

a[1][3]

a[2][2]

a[2][3]

a

a+1

a+2

p

p+1

p+2

p[0]+1 或 *p+1

p[1]+2 或 *(p+1)+2

*(*p+1) 或 (*p)[1]

*(*(p+1)+2)

一维数组指针变量维数和二维数组列数必须相同

Page 51: 第十章   指    针

51

C 语言程序设计 第十章 指针

0 1 2 3

4 5 6 7

 8  9 10 11

a[0]

a[1]

a[2]

a, p

a+2, p+2

a+1, p+1

*p+0 *p+1*p+2

*p+3数组名 a 为数组的首地址

int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};

int i,j, (*p)[4];

p=a;

数组 a 的元素 a[i]j] 的表示:*(*(a+i)+j), *(*(p+i)+j)

*(a[i]+j) , *(p[i]+j)

Page 52: 第十章   指    针

52

C 语言程序设计 第十章 指针例 10.12(a) 用行指针 输出main()

{ int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};

int i,j,(*p)[4];

p=&a[0];

for(i=0;i<3;i++)

{

for(j=0;j<4;j++)

printf("%2d ",*(*(p+i)+j) );

printf("\n");

}

}

Page 53: 第十章   指    针

53

C 语言程序设计 第十章 指针

3. 多维数组的指针作函数的参数二维数组的指针作函数参数

(1) 用二维数组名 (2) 用指向变量的指针变量

(3) 用指向一维数组的指针变量

实参 形参数组名 int x[][4]

指针变量 int (*q)[4]

数组名 int x[][4]

指针变量 int (*q)[4]

数组名 a

数组名 a

指针变量 p1

指针变量 p1

若 int a[3][4]; int (*p1)[4]=a; int *p2=a[0];

指针变量 p2 指针变量 int *q

Page 54: 第十章   指    针

54

C 语言程序设计 第十章 指针

例 10-14 3 个学生各学 4 门课,计算总平均分,并输出第 n 个学生成绩

main(){ void average(float *p,int n); void search(float (*p)[4],int n); float score[3][4]={{65,67,79,60},{80,87,90,81},{90,99,100,98}}; average(*score,12); search(score,2);}

void average(float *p,int n){ float *p_end, sum=0,aver; p_end=p+n-1; for(;p<=p_end;p++)

sum=sum+(*p); aver=sum/n; printf("average=%5.2f\n",aver);}void search(float (*p)[4], int n){ int i; printf(" No.%d :\n",n); for(i=0;i<4;i++) printf("%5.2f ",*(*(p+n)+i));}

列指针

行指针

函数说明

float p[][4]

65 52 79 60

80 87 90 81

90 99 100 98

p

p

p[n][i]

Page 55: 第十章   指    针

55

C 语言程序设计 第十章 指针例 10-15 3 个学生各学 4 门课, ( 计算总平均分, ) 并查找一门以上 课 不及格学生, 输出其各门课成绩void search(float (*p)[4], int n)

{ int i,j,flag; for(j=0;j<n;j++) { flag=0;

for(i=0;i<4;i++) if(*(*(p+j)+i)<60) flag=1;if(flag==1){ printf("No.%d is fail,his scores are:\n",j+1); for(i=0;i<4;i++)

printf("%5.1f ",*(*(p+j)+i)); printf("\n");}

}}

main(){ void search(float (*p)[4], int n); float score[3][4]={{...},{...},{...}}; search(score,3);}

65 57 70 60

58 87 90 81

90 99 100 98

p

p[j][i]

Page 56: 第十章   指    针

56

C 语言程序设计 第十章 指针

二维数组与一维数组指针变量的关系 如 int a[5][10] 与 int (*p)[10];

二维数组名是一个指向有 10 个元素的一维数组的指针常量 p=a+i 使 p 指向二维数组的第 i行 *(*(p+i)+j) a[i][j] 二维数组形参实际上是一维数组指针变量, 即 int x[ ][10] int (*x)[10] 变量定义 ( 不是形参)时两者不等价 系统只给 p 分配能保存一个指针值的内存区 ( 一般 2 字节);

而给 a 分配 2*5*10 字节的内存区

Page 57: 第十章   指    针

57

C 语言程序设计 第十章 指针

10.4 字符串的指针和指向字符串的指针变量 指向字符串的指针变量的定义与指向字符变量的指针变量说明是相同的。只能按对指针变量的赋值不同来区别。 对指向字符变量的指针变量应赋予该字符变量的地址。如: char c,*p=&c; 表示 p 是一个指向字符变量 c 的指针变量。而: char *s="C Language"; 则表示 s 是一个指向字符串的指针变量。把字符串的首地址赋予 s 。例 : main()

{ char *ps;

ps="C Language";

printf("%s",ps);

}

char *ps="C Language";

Page 58: 第十章   指    针

58

C 语言程序设计 第十章 指针 字符串表示形式

• 用字符数组实现

例 main( ) { char string[]=" I love China! "; printf("%s\n",string); printf("%s\n",string+7); }

I

love

Chi

string[0]string[1]string[2]string[3]string[4]string[5]string[6]string[7]string[8]string[9]

string

string[10]string[11]string[12]string[13]

n

!a

\0

Page 59: 第十章   指    针

59

C 语言程序设计 第十章 指针• 用字符指针实现

例 10-16.c main( ) { char *string=" I love China! "; printf("%s\n",string); string+=7; while(*string) { putchar(string[0]); string++; } }

I

love

Chi

string

n

!a

\0

字符指针初始化 :把字符串首地址赋给 string char *string; string=“I love China!”;

string

*string!=0

Page 60: 第十章   指    针

60

C 语言程序设计 第十章 指针

例:输出字符串中 n 个字符后的所有字符。main(){ char *ps="this is a book"; int n=10; ps=ps+n; printf("%s\n",ps);}运行结果为: book

例:字符串的复制main(){ char a[]="this is a book",b[16]; int n; for(n=0;a[n]!='\0';n++) *(b+n)=*(a+n); *(b+n)='\0'; printf("%s",b);}

Page 61: 第十章   指    针

61

C 语言程序设计 第十章 指针

T

ih

s

p1

p1

is

a

bo

k\0

o

T

ih

s

p2

p2

is

a

bo

k\0

o

a b例:字符串的复制main(){ char a[]="this is a book" ; char b[16],*p1,*p2; p1=a;p2=b; while(*p1!='\0') *p2++=*p1++; *p2='\0'; p2=b; printf("%s",p2);}

问能否将程序写成如下形式 ?main(){ char *p1="this is a book"; char *p2; while(*p1!='\0') . . . /* 以下与上面相同 */}

Page 62: 第十章   指    针

62

C 语言程序设计 第十章 指针

例 Y7-3 :利用字符指针求字符串中各种字符的个数

main(){ char str[200]; int count[3]={0}; char *pstr; char ch;

gets(str); pstr=str; while(*pstr!=0) { ch=*pstr; ch=toupper(ch);

if(ch>='A'&&ch<='Z') count[0]++; else if(ch>='0'&&ch<='9') count[1]++; else count[2]++; pstr++; } //while printf(“this string contains\ %d letters, %d digits and %d\ other characters\n", count[0],count[1],count[2]); }

Page 63: 第十章   指    针

63

C 语言程序设计 第十章 指针

二、字符串指针作为函数的参数 把字符串指针作为函数参数的使用,传递字符串或字符数组的首地址。

1 、当形参是字符数组时,要求对应的实参为: 字符数组名或字符指针变量2 、当形参是字符指针变量,要求对应的实参为: 字符指针变量或数组名

形式参数

字符指针变量

字符数组名

实参数

字符指针变量

字符数组名

①②

③④

Page 64: 第十章   指    针

64

C 语言程序设计 第十章 指针

把字符串指针作为函数参数的使用。 例:要求把一个字符串的内容复制到另一个字符串中,并且不能使用 strcpy 函数。cpystr(char *pss,char *pds){ while((*pds=*pss)!='\0'){ pds++; pss++; } }

main(){ char *pa="CHINA",b[10],*pb; pb=b; cpystr(pa,pb); printf("string a=%s\nstring b=%s\n",pa,pb); }

while((*pds++=*pss++)!='\0');

Page 65: 第十章   指    针

65

C 语言程序设计 第十章 指针

使用字符数组和字符指针变量处理字符串时应注意的几个问题:  1 、 字符串指针变量本身是一个变量,用于存放字符串的首地址。而字符串本身是存放在以该首地址为首的一块连续的内存空间中并以‘ \0’ 作为串的结束。字符数组是由于若干个数组元素组成的,它可用来存放整个字符串。 2 、对字符数组作初始化赋值,必须采用外部类型或静态类型, 如: static char st[]={“C Language”};

而对字符串指针变量则无此限制,如: char *ps="C Languag

e";

3 、 对字符串指针方式 char *ps="C Language";

可以写为: char *ps; ps="C Language";

而对数组方式: static char st[]={"C Language"};

不能写为: char st[20]; st={"C Language"};

而只能对字符数组的各元素逐个赋值。

Page 66: 第十章   指    针

66

C 语言程序设计 第十章 指针 字符指针变量与字符数组

char *cp; 与 char str[20];

• str 由若干元素组成,每个元素放一个字符;而 cp 中存放字符串首地址

• char str[20]; str=“I love China!”; ()

char *cp; cp=“I love China!”; ()

• str 是地址常量; cp 是地址变量• cp 接受键入字符串时 , 必须先开辟存储空间

例 char str[10]; scanf(“%s”,str); ()

而 char *cp; scanf(“%s”, cp); ()

改为 : char *cp,str[10]; cp=str; scanf(“%s”,cp); ()

Page 67: 第十章   指    针

67

C 语言程序设计 第十章 指针

10.5 函数的指针和指向函数的指针变量 概念:在C语言中规定,一个函数总是占用一段连续的内存区, 而函数名就是该函数所占内存区的首地址。 我们可以把函数的首地址 ( 或称入口地址 ) 称为“函数的指针”,把函数的指针赋予一个指针变量,使该指针变量指向该函数。然后通过指针变量就可以找到并调用这个函数。 我们把这种指向函数的指针变量称为“指向函数的指针变量”,也称函数指针变量。 一、函数指针变量定义的一般形式为:

类型说明符 (* 指针变量名 )();

其中“类型说明符”表示被指函数的返回值的类型。 “(* 指针变量名 )” 表示“ *”后面的变量是定义的指针变量。 最后的空括号表示指针变量所指的是一个函数。

Page 68: 第十章   指    针

68

C 语言程序设计 第十章 指针函数指针:函数在编译时被分配的入口地址 ,

用函数名表示max

….

..

指令 1指令 2

• 函数指针变量赋值 : 如 p=max;函数返回值的数据类型专门存放函数入口地址

可指向返回值类型相同的不同函数

指向函数的指针变量• 定义形式: 数据类型 (* 指针变量名 )();

如 int (*p)();

函数指针变量指向的函数必须有函数说明• 函数调用形式: c=max(a,b); c=(*p)(a,b); c=p (a,b);

• 对函数指针变量 pn, p++, p-- 无意义

( ) 不能省int (*p)() 与 int *p() 不同

Page 69: 第十章   指    针

69

C 语言程序设计 第十章 指针

例如: int (*pf)();

表示 pf 是一个指向函数入口的指针变量,该函数的返回值( 函数值 ) 是整型。 下面通过例子来说明用指针形式实现对函数调用的方法。int max(int a,int b){ if(a>b)return a; else return b;}main(){ int (*pmax)(); int x,y,z; pmax=max; printf("input two numbers:\n"); scanf("%d%d",&x,&y); z=(*pmax)(x,y); printf("maxmum=%d",z);}

命令 1pmax

命令 2

. . .

Page 70: 第十章   指    针

70

C 语言程序设计 第十章 指针 从上述程序可以看出,用函数指针变量形式调用函数的步骤如下: 1. 先定义函数指针变量, 如: int (*pmax)(); 定义 pmax 为函数指针变量。 2. 把被调函数的入口地址 ( 函数名 ) 赋予该函数指针变量,如程序中的 pmax=max;

3. 用函数指针变量形式调用函数,如程序中 z=(*pmax)(x,y);

调用函数的一般形式为: (* 指针变量名 ) (实参表 ) 使用函数指针变量还应注意以下两点: a. 函数指针变量不能进行算术运算,这是与数组指针变量不同的。数组指针变量加减一个整数可使指针移动指向后面或前面的数组元素,而函数指针的移动是毫无意义的。 b. 函数调用中“ (* 指针变量名 )” 的两边的括号不可少,其中的 * 不应该理解为求值运算,在此处它只是一种表示符号。 ( 例 P243 )

Page 71: 第十章   指    针

71

C 语言程序设计 第十章 指针 二 . 用函数指针变量作函数参数

例 10-24 用函数指针变量作参数,求最大值、最小值和两数之和void main(){ int a,b,max(int,int), min(int,int),add(int,int); void process(int,int,int (*fun)()); scanf("%d,%d",&a,&b); process(a,b,max); process(a,b,min); process(a,b,add);}void process(int x,int y,int (*fun)()){ int result; result=(*fun)(x,y); printf("%d\n",result);}

max(int x,int y){ printf(“max=”);printf(“max=”); return(x>y?x:y);return(x>y?x:y);}min(int x,int y){ printf(“min=”);printf(“min=”); return(x<y?x:y);return(x<y?x:y);}add(int x,int y){ printf(“sum=”); printf(“sum=”); return(x+y);return(x+y);}

Page 72: 第十章   指    针

72

C 语言程序设计 第十章 指针

10.6 返回指针值的函数 前面我们介绍过,所谓函数类型是指函数返回值的类型。 在C语言中允许一个函数的返回值是一个指针 ( 即地址 ) , 这种返回指针值的函数称为指针型函数。 定义指针型函数的一般形式为: 类型说明符 * 函数名 ( 形参表 ) { …… /* 函数体 */ } 其中函数名之前加了“ *” 号表明这是一个指针型函数,即返回值是一个指针。类型说明符表示了返回的指针值所指向的数据类型。

Page 73: 第十章   指    针

73

C 语言程序设计 第十章 指针如: int *ap(int x,int y) { ...... /* 函数体 */ } 表示 ap 是一个返回指针值的指针型函数, 它返回的指针指向一个整型变量。

注意的是函数指针变量和指针型函数在写法和意义上的区别。如 int (*p)() 和 int *p() 是两个完全不同的量。 int (*p)() 是一个变量说明,说明 p 是一个指向函数入口的指针变量,该函数的返回值是整型量。 int *p() 则不是变量说明而是函数说明,说明 p 是一个指针型函数,其返回值是一个指向整型量的指针, *p 两边没有括号。

Page 74: 第十章   指    针

74

C 语言程序设计 第十章 指针

main() { int i; char *day_name(int n); printf("input Day No:\n"); scanf("%d",&i); if(i<0) exit(1); printf("Day No:%2d-->%s\n",i,day_name(i)); }char *day_name(int n) {char *name[]={ "Illegal day", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; return((n<1||n>7) ? name[0] : name[n]); }

Page 75: 第十章   指    针

75

C 语言程序设计 第十章 指针返回指针值的函数

函数定义形式: 类型标识符 * 函数名 ( 参数表 );

例 int *f(int x, int y)

例 p.24610-25 指针函数实现:有若干学生成绩,要求输入学生序号后, 能输出其全部成绩

main(){ float score[][4]={{60,70,80,90},

{56,89,67,88},{34,78,90,66}}; float *search(float (*pointer)[4],int n), *p; int i,m; printf("Enter the number of student:"); scanf("%d",&m); printf("The scores of No.%d are:\n",m); p=search(score,m); for(i=0;i<4;i++) printf("%5.2f\t",*(p+i));}float *search(float (*pointer)[4], int n){ float *pt; pt=*(pointer+n); return(pt);}

pointer

pointer+1

34 78 90 66

56 89 67 88

60 70 80 90

score 数组

p p p p

Page 76: 第十章   指    针

76

C 语言程序设计 第十章 指针

10.7 指针数组和指向指针的指针一、指针数组的概念 一个数组的元素值为指针则这个数组称为是指针数组。 指针数组是一组有序的指针的集合。 指针数组的所有元素都必须是具有相同存储类型和指向相同数据类型的指针变量。 指针数组说明的一般形式为: 类型说明符 * 数组名 [ 数组长度 ]

其中类型说明符为指针值所指向的变量的类型。 例如: int *pa[3] ; 表示 pa 是一个指针数组,它有三个数组元素, 每个元素值都是一个指针,指向整型变量。

Page 77: 第十章   指    针

77

C 语言程序设计 第十章 指针

用于处理二维数组或多个字符串 指针数组

• 定义:数组中的元素为指针变量• 定义形式: [ 存储类型 ] 数据类型 * 数组名 [ 数组长度

说明 ] ;例 int *p[4];

指针所指向变量的数据类型指针本身的存储类型区分 int *p[4] 与 int (*p)[4]• 指针数组赋值与初始化赋值 :main(){ int b[2][3],*pb[2]; pb[0]=b[0]; pb[1]=b[1]; ……..}

int *pb[2]

pb[0]pb[1]

int b[2][3]

1

2

3

2

4

6

初始化 :main(){ int b[2][3],*pb[ ]={b[0],b[1]}; ……..}

int *pb[2]

pb[0]pb[1]

int b[2][3]

1

2

3

2

4

6

Page 78: 第十章   指    针

78

C 语言程序设计 第十章 指针

指针数组 二维数组的指针

变量定义 int *p[10] int (*p)[10]

变量性质 P 是数组名,不是指针变量,不能对 p 赋值

P 是指针变量,不是数组名,可以对 p 赋值

Page 79: 第十章   指    针

79

C 语言程序设计 第十章 指针

输出 12 个月:

main() { int i; for(i=0; i<13; i++) printf("%s\n", month_name(i)); }

Page 80: 第十章   指    针

80

C 语言程序设计 第十章 指针char *month_name(int n) { static char *name[]={ "Illegal month", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };

return((n<1||n>12)?name[0]:name[n]); }

输出 12 个月:

main() { int i; for(i=0; i<13; i++) printf("%s\n", month_name(i)); }

Page 81: 第十章   指    针

81

C 语言程序设计 第十章 指针

例 Y7-4a :输入多个学生的名字,按升序输出 ( 数组) *自学*

include <stdio.h>#include <conio.h>#define STUNUM 10main(){ char name[STUNUM][20]; char str[80]; int i,j,k,num;

num=0; for(i=0;i<STUNUM;i++)

{ printf("input the name of the %dth student:",i+1); gets(str); if(str[0]==0) break; if(strlen(str)>19) { i--; continue; } strcpy(name[i],str); num++; }

Page 82: 第十章   指    针

82

C 语言程序设计 第十章 指针

for(j=1;j<=num-1;j++) { k=num-j; for(i=0;i<num-j;i++) if(stricmp(name[i],name[k])>0)

k=i; if(k!=num-j) { strcpy(str,name[k]); strcpy(name[k],name[num-j]); strcpy(name[num-j],str);

} } for(i=0;i<num;i++) printf("%dth:%s\n",i+1,name[i]);

}

Page 83: 第十章   指    针

83

C 语言程序设计 第十章 指针例 Y7-4b :输入多个学生的名字,按升序输出 (指针) *自学*

#include <stdio.h>#include <conio.h>#define STUNUM 10main(){ char name[STUNUM][20]; char str[80]; char *pstr[STUNUM]; int i,j,k,num;

num=0; for(i=0;i<STUNUM;i++)

{ printf("input the name of the %dth student:",i+1); gets(str); if(str[0]==0) break; if(strlen(str)>19) { i--; continue; } strcpy(name[i],str); num++; }for(i=0;i<num;i++) pstr[i]=name[i];

Page 84: 第十章   指    针

84

C 语言程序设计 第十章 指针

for(j=1;j<=num-1;j++) { k=num-j; for(i=0;i<num-j;i++) if(stricmp(pstr[i],pstr[k])>0)

k=i; if(k!=num-j) { char *ptmp; ptmp=pstr[k]; pstr[k]=pstr[num-j]; pstr[num-j]=ptmp;

} } for(i=0;i<num;i++) printf("%dth:%s\n",i+1,pstr[i]);

}

Page 85: 第十章   指    针

85

C 语言程序设计 第十章 指针

main(){ int b[2][3],*pb[2]; int i,j; for(i=0;i<2;i++) for(j=0;j<3;j++)

b[i][j]=(i+1)*(j+1); pb[0]=b[0]; pb[1]=b[1]; for(i=0;i<2;i++) for(j=0;j<3;j++,pb[i]++)

printf("b[%d][%d]:%2d\n",i,j,*pb[i]);}

例 10-26b 用指针数组处理二维数组 *自学 *

int *pb[2]

pb[0]pb[1]

int b[2][3]b[0][0] *pb[0]

b[0][1] *(pb[0]+1)

b[0][2] *(pb[0]+2)

b[1][0] *pb[1]

b[1][1] *(pb[1]+1)

b[1][2] *(pb[1]+2)

1

2

3

2

4

6

Page 86: 第十章   指    针

86

C 语言程序设计 第十章 指针

例 p.249 10-27 :由字符指针数组处理多个字符串的问题 (zb33)#include "string.h"main(){ void sort(char *name[],int n); void print(char *name[],int n); char *name[]={ "CHINA","AMERICA", "AUSTRALIA", "FRANCE","GERMAN"}; int n=5; sort(name,n); print(name,n);}

Page 87: 第十章   指    针

87

C 语言程序设计 第十章 指针void sort(char *name[],int n){ char *pt; int i,j,k; for(i=0;i<n-1;i++) { k=i; for(j=i+1;j<n;j++) if(strcmp(name[k],name[j])>0) k=j; if(k!=i) { pt=name[i]; name[i]=name[k]; name[k]=pt; } }}

void print(char *name[],int n){ int i; for (i=0;i<n;i++) printf("%s\n",name[i]);}

Page 88: 第十章   指    针

88

C 语言程序设计 第十章 指针

二、指向指针的指针

指针数组名同样表示指针数组的首地址,是一个指针变量的地址,即是指针的指针。

指针变量在内存中仍有一个存储单元,该单元的地址,即指针的指针。如下图:

a

10

p

&a

pp

&p

指向指针的指针变量的定义:

int a, *p=a;**pp=&p;

类型说明符 ** 指针名

Page 89: 第十章   指    针

89

C 语言程序设计 第十章 指针

例 p.252 10-29 输出 a[5]

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,i; p=num; for(i=0;i<5;i++) { printf("%d\n",**p); p++; } }

Page 90: 第十章   指    针

90

C 语言程序设计 第十章 指针

三、 main() 函数的参数 前面介绍的 main 函数都是不带参数的。因此 main 后的括号都是空括号。实际上, main 函数可以带参数,这个参数可以认为是 main 函数的形式参数。C语言规定 main 函数的参数只能有两个, 习惯上这两个参数写为 argc 和 argv 。因此, main 函数的函数头可写为: main (argc,argv) C语言还规定 argc( 第一个形参 ) 必须是整型变量 ,argv( 第二个形参 ) 必须是指向字符串的指针数组。加上形参说明后, main

函数的函数头应写为: main (argc,argv)

int argv;

char *argv[];

或写成: main (int argc,char *argv[])

Page 91: 第十章   指    针

91

C 语言程序设计 第十章 指针

说明:由于 main 函数不能被其它函数调用, 因此不可能在程序内部取得实际值。那么,在何处把实参值赋予 main 函数的形参呢 ?

实际上 ,main 函数的参数值是从操作系统命令行上获得的。当我们要运行一个可执行文件时,在 DOS 提示符下键入文件名,再输入实际参数即可把这些实参传送到 main 的形参中去。DOS 提示符下命令行的一般形式为:

C:\> 可执行文件名 参数 参数…… ; 注意: main 的两个形参和命令行中的参数在位置上不是一一对应的。因为 ,main 的形参只有二个,而命令行中的参数个数原则上未加限制。 argc参数表示了命令行中参数的个数( 注意:文件名本身也算一个参数 ) , argc 的值是在输入命令行时由系统按实际参数的个数自动赋予的。

Page 92: 第十章   指    针

92

C 语言程序设计 第十章 指针例如有命令行为: C:\>E624 BASIC dbase FORTRAN 由于文件名 E624 本身也算一个参数,所以共有 4 个参数,因此 argc 取得的值为 4 。 argv参数是字符串指针数组,其各元素值为命令行中各字符串 (参数均按字符串处理 ) 的首地址。 指针数组的长度即为参数个数。数组元素初值由系统自动赋予。 main(int argc,char *argv[]) { while(argc-->1) printf("%s\n",*++argv); }本例是显示命令行中输入的参数 如果上例的可执行文件名为 e24.exe ,存放在 A驱动器的盘内。因此输入的命令行为: C:\>a:e24 BASIC dBASE FORTRAN 则运行结果为: BASIC dBASE FORTRAN

Page 93: 第十章   指    针

93

C 语言程序设计 第十章 指针

#include <stdio.h>

char *week_str[]={ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };

例 Y7-8 :利用命令行参数输出星期一到星期日的英文名 *自学

*

Page 94: 第十章   指    针

94

C 语言程序设计 第十章 指针void main(int argc,char *argv[]){ int k; if(argc==2) { sscanf(argv[1],"%d",&k); if(k>7) { printf("command line argument must be in [1..7]\n"); return; } printf("%s\n",week_str[k-1]); } else { printf("use this program like this: Y7-8 3\n"); } }

Page 95: 第十章   指    针

95

C 语言程序设计 第十章 指针

定义 含义int i;

int *p;

int a[n];

int *p[n];

int (*p)[n];

int f();

int *p();

int (*p)();

int **p;

定义整型变量 i

p 为指向整型数据的指针变量

定义含 n 个元素的整型数组 a

n 个指向整型数据的指针变量组成的指针数组 p

p 为指向含 n 个元素的一维整型数组的指针变量

f 为返回整型数的函数

p 为返回指针的函数,该指针指向一个整型数据

p 为指向函数的指针变量,该函数返回整型数p 为指针变量,它指向一个指向整型数据的指针变量

指针的数据类型

Page 96: 第十章   指    针

96

C 语言程序设计 第十章 指针

例 下列定义的含义( 1 ) int *p[3];( 2 ) int (*p)[3];( 3 ) int *p(int);( 4 ) int (*p)(int);( 5 ) int *(*p)(int);( 6 ) int (*p[3])(int);( 7 ) int *(*p[3])(int); 函数指针数组,函数返回 int 型指针

指针数组指向一维数组的指针返回指针的函数

指向函数的指针,函数返回 int 型变量指向函数的指针,函数返回 int 型指针函数指针数组,函数返回 int 型变量

Page 97: 第十章   指    针

97

C 语言程序设计 第十章 指针

实验 8.1 解法一:main(){ int i, j, a[3][6], *p, imin=0, jmin=0, imax=0, jmax=0; printf(“Please input the Array :\n”); p=*a; for(i=0;i<3;i++) for(j=0;j<6;j++) { scanf(“%d”,p); if (*p>a[imax][jmax]) { imax=i; jmax=j;} else if (*p<a[imin][jmin]) { imin=i; jmin=j;} p++; } printf(“The max is %d,”,a[imax][jmax]); printf(“It is a[%d][%d]\n”,imax, jmax); printf(“The min is %d,”,a[imin][jmin]); printf(“It is a[%d][%d]\n”,imin, jmin);}

Page 98: 第十章   指    针

98

C 语言程序设计 第十章 指针实验 8.1 解法二:int max,min;void max_min_value(int *p,int n){int i;int *p_end;p_end=p+n;max=*p;min=*p;for(;p<p_end;p++){if(*p > max) max=*p;else if(*p<min) min=*p;}printf("\n===max=%d,min=%d\n",

max,min);return;}

main(){ int i,j; int a[3][6]= {{11,2,3,4,56,67}, {3,4,5,7,8,9}, {12,25,35,58,98,100}};max_min_value(*a,18);printf("\nmax=%d, min=%d\n",max,min);}

Page 99: 第十章   指    针

99

C 语言程序设计 第十章 指针实验 8.1 解法三:int max,min, q1,t1,q2,t2;void max_min_value(int (*p)[6]){int i,j;

max=min=*(*p);

for(i=0;i<3;i++)for(j=0;j<6;j++)

if(*(*(p+i)+j)>max){max=*(*(p+i)+j);q1=i,t1=j; }

else if(*(*(p+i)+j)<min){min=*(*(p+i)+j);q2=i,t2=j; }

return;}

main(){int a[3][6]={{1,2,3,4,5,6},{7,8,9,10,11,12},{13,14,15,16,17,18}};

max_min_value(a);

printf("max=%d,min=%d,q1=%d,t1=%d.q2=%d,t2=%d\n",max,min,q1,t1,q2,t2);}

Page 100: 第十章   指    针

100

C 语言程序设计 第十章 指针

实验 8.1 解法四:

int max,min,q1,t1,q2,t2;void max_min_value(int *p[3]){int i,j;

max=min=**p;

for(i=0;i<3;i++)for(j=0;j<6;j++)

if(*(p[i]+j)>max) {max=*(p[i]+j);q1=i,t1=j; }else if(*(p[i]+j)<min) {min=*(p[i]+j);q2=i,t2=j; }

return;}

Page 101: 第十章   指    针

101

C 语言程序设计 第十章 指针

main(){int i,j,a[3][6]={{11,2,3,4,5,6},

{7,8,9,10,1,122},{13,14,15,16,17,18}};

int *p[3];p[0]=a[0];p[1]=a[1];p[2]=a[2];

max_min_value(a);

printf("max=%d,min=%d,*q1=%d,*t1=%d.*q2=%d,*t2=%d\n",

max,min,q1,t1,q2,t2);

Page 102: 第十章   指    针

102

C 语言程序设计 第十章 指针实验 8.2 解法一: conv(int (*p)[3]){ int i, j, t; for(i=0;i<3;i++) for(j=i;j<3;j++) { t=*(*(p+i)+j); *(*(p+i)+j)=*(*(p+j)+i); *(*(p+j)+i)=t; } }main(){ int a[3][3], i, j; printf(“Please input the Array :\n”); for(i=0;i<3;i++) for(j=0;j<3;j++)

scanf(“%d”,&a[i][j]); conv(a); for(i=0;i<3;i++) { for(j=0;j<3;j++) printf(“%4d”,a[i][j]); printf(“\n”); } }

Page 103: 第十章   指    针

103

C 语言程序设计 第十章 指针实验 8.2 解法二:main(){int a[3][3]={{1,3,5},{7,9,11},{13,15,19}};int *p,i;p=&a[0][0];move(*a); move(p);for(i=0;i<3;i++)printf("%d %d %d\n",a[i][0],a[i][1],a[i][2]);}move(int *p){int i,j,t;for(i=0;i<3;i++)for(j=i;j<3;j++){t=*(p+3*i+j); *(p+3*i+j)=*(p+3*j+i); *(p+3*j+i)=t; }}

Page 104: 第十章   指    针

104

C 语言程序设计 第十章 指针一、判断题:

1. 设变量定义为 char s[]=“hello”, 则数组 s中有 6个元素。

2.a是一维数组名,数组元素a[1]还可以写作“ *(a++)”

Page 105: 第十章   指    针

105

C 语言程序设计 第十章 指针二、单选题:

1. 下列程序段的输出结果是——。 int c[]={1,7,12}; int *k=c+1; printf(“%d”,*k++);A. 2 B. 7 c.8 d.12

2. 下列程序段的输出结果是——。 char *st[]={“abcd”,”efgh”,”ijkl”,“mnop”},**p=st; p++; printf(*p+1);A. cd B. fgh c.ijkl d.出错

3.int a[3][4]; 与数组元素a[2][1]等价的是A. *(a[2]+1) B. a[9] c. *(a[1]+2) d. *(*a+2)+1

Page 106: 第十章   指    针

106

C 语言程序设计 第十章 指针三、程序填空题:

1. 一维数组 函数

2. 一维数组指针 函数

3. 结构体

4. 文件

Page 107: 第十章   指    针

107

C 语言程序设计 第十章 指针四、程序阅读题:

1. 一维数组 函数二维数组

2. 一维数组指针 函数二维数组指针 指导p.36 (2)

字符串指针

3. 结构体 链表

4. 文件

Page 108: 第十章   指    针

108

C 语言程序设计 第十章 指针五、程序设计题:

一维数组 函数 (一维数组指针 函数)

1. 求 1+1/2!+1/3!+…+1/n!

调用函数 fact(n)计算 n!

2.统计 字母 数字 其他字符个数