Ch10 指针

71
1 第第第 第第 Ch10 第第 第第第第第第第第第 第第第第 第第第第第 第第第第第第 第第第第第 第第第第第第第第 第第第第第第第第第

description

Ch10 指针. 内容提要: ★指针的概念 ★指针变量 ★指针与数组 ★指针与字符串 ★指针与函数 ★返回指针值的函数 ★指针数组和多级指针. 内存. 0. …. 2000. 2001. 2002. 2003. 2005. …. 内存中每个字节有一个编号 ----- 地址. 10.1 指针的概念 变量与地址. 程序中 : int i; float k;. i. - PowerPoint PPT Presentation

Transcript of Ch10 指针

Page 1: Ch10    指针

1

第十章 指针

Ch10 指针内容提要:

★ 指针的概念

★ 指针变量

★ 指针与数组

★ 指针与字符串

★ 指针与函数

★ 返回指针值的函数

★ 指针数组和多级指针

Page 2: Ch10    指针

2

第十章 指针• 10.1 指针的概念

– 变量与地址

程序中 : int i;

float k;

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

….

..…

...

2000

2001

2002

2005

内存0

2003

i

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

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

Page 3: Ch10    指针

3

第十章 指针

….

..…

...

2000

2004

2006

2005

整型变量 i10

变量 i_pointer

2001

2002

2003

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

2000

指针

指针变量

变量的内容 变量的地址

指针变量

变量

变量地址 ( 指针 )

变量值指向 地址存入

指针变量

Page 4: Ch10    指针

4

第十章 指针– & 与 * 运算符

• 含义含义 : 取变量的地址单目运算符优先级 : 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 5: Ch10    指针

5

第十章 指针– 直接访问与间接访问

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

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

指针变量

….

..…

...

2000

2004

2006

2005

整型变量 i10

变量 i_pointer

2001

2002

2003

2000

3

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

20

Page 6: Ch10    指针

6

第十章 指针

指针变量…

...

….

..

2000

2004

2006

2005

整型变量 i10

变量 i_pointer

2001

2002

2003

2000

整型变量 k

例 k=i; -- 直接访问 k=*i_pointer; -- 间接访问

10

例 k=i; k=*i_pointer;

Page 7: Ch10    指针

7

第十章 指针• 10.2 指针变量

指针变量与其所指向的变量之间的关系

– 指针变量的定义• 一般形式: [ 存储类型 ] 数据类型 * 指针名;

3

变量 i

2000

i_pointer

*i_pointer

i *i_pointer&i i_pointer

i=3; *i_pointer=33

变量 i

2000

i_pointer

*i_pointer

i *i_pointer&i i_pointer

i=3; *i_pointer=3

合法标识符指针变量本身的存储类型指针的目标变量的数据类型表示定义指针变量不是‘ *’ 运算符

例 int *p1,*p2; float *q ; static char *name;

注意:1 、 int *p1, *p2; 与 int *p1, p2;2 、指针变量名是 p1,p2 , 不是 *p1,*p23 、指针变量只能指向定义时所规定类型的变量4 、指针变量定义后,变量值不确定,应用前必须先赋值

Page 8: Ch10    指针

8

第十章 指针– 指针变量的初始化

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

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

例 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 型指针()

10-1.c

Page 9: Ch10    指针

9

第十章 指针

例 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 10: Ch10    指针

10

第十章 指针– 零指针与空类型指针

• 零指针: ( 空指针 )– 定义 : 指针变量值为零– 表示: int * p=0;

p 指向地址为 0的单元,系统保证该单元不作它用表示指针变量值没有意义

#define NULL 0int *p=NULL:

– p=NULL与未对 p 赋值不同– 用途 :

» 避免指针变量的非法引用» 在程序中常作为状态比较

例 int *p; ...... while(p!=NULL) { ...… }

• void * 类型指针– 表示 : void *p;

– 使用时要进行强制类型转换

例 char *p1; void *p2; p1=(char *)p2; p2=(void *)p1;表示不指定 p是指向哪一

种类型数据的指针变量

Page 11: Ch10    指针

11

第十章 指针

例 指针的概念

main(){ int a; int *pa=&a; a=10; printf("a:%d\n",a); printf("*pa:%d\n",*pa); printf("&a:%x(hex)\n",&a); printf("pa:%x(hex)\n",pa); printf("&pa:%x(hex)\n",&pa);}

运行结果:a:10*pa:10&a:f86(hex)pa:f86(hex)&pa:f88(hex)

….

..…

...

f86

f8a

f8c

f8b

整型变量 a10

指针变量 paf87

f88

f89 f86

Ch9_0.c

Page 12: Ch10    指针

12

第十章 指针例 : 输入两个数,并使其从大到小输出

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("a=%d,b=%d\n",a,b); printf("max=%d,min=%d\n",*p1,*p2);}

运行结果: a=5,b=9 max=9,min=5

….

..…

...

指针变量 p1

指针变量 p

2000

2008

2002

2004

2006

指针变量 p2

整型变量 b

整型变量 a5

2006

9

20082006

2008

2006

Ch9_01.c

Page 13: Ch10    指针

13

第十章 指针– 指针变量作为函数参数——地址传递

特点:共享内存 ,“ 双向”传递

swap(int x,int y){ int temp; temp=x; x=y; y=temp;}main(){ int a,b; scanf("%d,%d",&a,&b); if(a<b) swap(a,b); printf("\n%d,%d\n",a,b);}

例 将数从大到小输出…

...

….

..

2000

2008

200A

2002

2004

2006

5变量 a

变量 b

(main)

9

变量 temp

变量 y

变量 x(swap)

5

5

959

COPY

Page 14: Ch10    指针

14

第十章 指针

swap(int x,int y){ int temp; temp=x; x=y; y=temp;

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

例 将数从大到小输出

值传递

….

..…

...

2000

2008

200A

2002

2004

2006

5变量 a

变量 b

(main)

9

运行结果: 5, 9

Page 15: Ch10    指针

15

第十章 指针

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

….

..

2000

2008

200A

2002

2004

2006

200C

200E

2010 ...

59

整型变量 a

整型变量 b

(main)

指针 pointer_1

指针 pointer_220002002(swap)

指针 p1

指针 p2

整型 p

59

20002002

COPY

5

例 将数从大到小输出 Ch9_03.c

Page 16: Ch10    指针

16

第十章 指针

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

….

..

2000

2008

200A

2002

2004

2006

200C

200E

2010 ...

59

整型变量 a

整型变量 b

(main)

指针 pointer_1

指针 pointer_220002002

59

例 将数从大到小输出

运行结果: 9 , 5

地址传递

Ch9_3.c

Page 17: Ch10    指针

17

第十章 指针

swap(int *p1, int *p2){ int *p; *p=*p1; *p1=*p2; *p2=*p;}main(){ int a,b; int *pointer_1,*pointer_2; scanf("%d,%d",&a,&b); pointer_1=&a; pointer_2=&b; if(a<b) swap(pointer_1,pointer_2); printf("\n%d,%d\n",a,b);} 运行结果: 9 , 9

例 将数从大到小输出

….

..

2000

2008

200A

2002

2004

2006

200C

200E

2010 ...

59

整型变量 a

整型变量 b

(main)

指针 pointer_1

指针 pointer_220002002

99

20002002

COPY (swap)指针 p1

指针 p2

指针 p**** 假设 2000

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

Ch9_31.c

int x;int *p=&x;

Page 18: Ch10    指针

18

第十章 指针

/*ch10_32.c*/swap(int x,int y){ int t; t=x; x=y; y=t;}main(){ int a,b; int *pointer_1,*pointer_2; scanf("%d,%d",&a,&b); pointer_1=&a; pointer_2=&b; if(a<b) swap(*pointer_1,*pointer_2); printf("\n%d,%d\n",a,b);}

运行结果: 5 , 9

例 将数从大到小输出

值传递…

...

2000

2008

200A

2002

2004

2006

200C

200E

2010 ...

59

整型 a

整型 b

(main)

pointer_1

pointer_220002002

9

COPY (swap)整型 x

整型 b

整型 t5559

Ch9_32.c

Page 19: Ch10    指针

19

第十章 指针

运行结果: 5 , 9

例 将数从大到小输出swap(int *p1, int *p2){ int *p; p=p1; p1=p2; p2=p;}main(){ int a,b; int *pointer_1,*pointer_2; scanf("%d,%d",&a,&b); pointer_1=&a; pointer_2=&b; if(a<b) swap(pointer_1,pointer_2); printf("%d,%d",*pointer_1,*pointer_2);}

….

..

2000

2008

200A

2002

2004

2006

200C

200E

2010 ...

59

整型 a

整型 b

(main)

pointer_1

pointer_220002002

20002002

COPY (swap)指针 p1

指针 p2

指针 p****2000

地址传递

20002002

Ch9_33.c

Page 20: Ch10    指针

20

第十章 指针

• 10.3 指针与数组– 指向数组元素的指针变量

例 int array[10]; int *p; p=&array[0]; // p=array;或 int *p=&array[0];或 int *p=array;

array[0]array[1]array[2]array[3]

array[9]

...

整型指针 p &array[0]

p

数组名是表示数组首地址的地址常量

Page 21: Ch10    指针

21

第十章 指针– 指针的运算

• 指针变量的赋值运算– p=&a; ( 将变量 a 地址 p)

– p=array; ( 将数组 array 首地址 p)

– p=&array[i]; ( 将数组元素地址 p)

– p1=p2; ( 指针变量 p2 值 p1)

– 不能把一个整数 p, 也不能把 p 的值整型变量

如 int i, *p; p=1000; () i=p; ()

•指针变量的关系运算– 若 p1 和 p2 指向同一数组,则

» p1<p2 表示 p1 指的元素在前» p1>p2 表示 p1 指的元素在后» p1==p2 表示 p1 与 p2 指向同一元素

– 若 p1 与 p2 不指向同一数组,比较无意义– p==NULL 或 p!=NULL

Page 22: Ch10    指针

22

第十章 指针•指针的算术运算:

–pi

–p++, p--, p+i, p-i, p+=i, p-=i 等–若 p1 与 p2 指向同一数组, p1-p2= 两指针间元素个数–p1+p2 无意义

例 p 指向 float 数,则 p+1 p+1 4

例 p 指向 int 型数组,且 p=&a[0]; 则 p+1 指向 a[1]

例 int a[10]; int *p=&a[2]; p++; *p=1;

例 int a[10]; int *p1=&a[2]; int *p2=&a[5]; 则: p2-p1=3;

a[0]

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

a[8]

a[9]

a 数组p

p+1,a+1

p+i,a+i

p+9,a+9

Page 23: Ch10    指针

23

第十章 指针– 数组元素表示方法

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

a[9]

...

a

a+9

a+1a+2

地址 元素

下标法

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

a[9]

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

a[9]

...

p

p+9

p+1p+2

地址 元素

指针法

*p*(p+1)*(p+2)

*(p+9)

[] 变址运算符a[i] *(a+i)

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

*a*(a+1)*(a+2)

*(a+9)

p[0]p[1]p[2]

p[9]

Page 24: Ch10    指针

24

第十章 指针

a[0]a[1]a[2]a[3]a[4]

例 数组元素的引用方法

main(){ int a[5],*pa,i; for(i=0;i<5;i++)

a[i]=i+1; pa=a; for(i=0;i<5;i++)

printf("*(pa+%d):%d\n",i,*(pa+i)); for(i=0;i<5;i++)

printf("*(a+%d):%d\n",i,*(a+i)); for(i=0;i<5;i++)

printf("pa[%d]:%d\n",i,pa[i]); for(i=0;i<5;i++)

printf("a[%d]:%d\n",i,a[i]);}

12345

pa

Ch10_1.c

Page 25: Ch10    指针

25

第十章 指针

例 void main() { int a []={5,8,7,6,2,7,3}; int y,*p=&a[1]; y=(*--p)++; printf(“%d ”,y); printf(“%d”,a[0]); }

输出: 5 6

pp 5

8

7

6

2

7

3

0

1

2

3

4

5

6

a

例 注意指针变量的运算

6

例 int a[]={1,2,3,4,5,6,7,8,9,10},*p=a,i; 数组元素地址的正确表示:( A ) &(a+1) ( B ) a++ ( C ) &p ( D ) &p[i]

Page 26: Ch10    指针

26

第十章 指针

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

for(i=0;i<7;i++,p++) printf("%d",*p);}

例 注意指针的当前值

p=a;

pp 5

8

7

6

2

7

3

0

1

2

3

4

5

6

a

p

p

p

p

p

p

指针变量可以指到数组后的内存单元

Ch9_6.c

Page 27: Ch10    指针

27

第十章 指针– 数组名作函数参数

• 数组名作函数参数,是地址传递• 数组名作函数参数,实参与形参的对应关系

实参 形参数组名

指针变量数组名

指针变量

数组名数组名指针变量指针变量

Page 28: Ch10    指针

28

第十章 指针

例 将数组 a 中的 n 个整数按相反顺序存放

i j

3 7 9 11 0 6 7 5 4 20 1 2 3 4 5 6 7 8 9

i ji ji jji

117 6 05 94 72 3

实参与形参均用数组

void inv(int x[], int n){ int t,i,j,m=(n-1)/2; for(i=0;i<=m;i++) { j=n-1-i;

t=x[i]; x[i]=x[j]; x[j]=t; }}main(){ int i,a[10]={3,7,9,11,0,6,7,5,4,2}; inv(a,10); printf("The array has been reverted:\n"); for(i=0;i<10;i++) printf("%d,",a[i]); printf("\n");}

m=4

Page 29: Ch10    指针

29

第十章 指针例 将数组 a 中的 n 个整数按相反顺序存放

void inv(int *x, int n){ int t,*p,*i,*j,m=(n-1)/2; i=x; j=x+n-1; p=x+m; for(;i<=p;i++,j--) { t=*i; *i=*j; *j=t; }}main(){ int i,a[10]={3,7,9,11,0,6,7,5,4,2}; inv(a,10); printf(" has been reverted:\n"); for(i=0;i<10;i++) printf("%d,",a[i]); printf("\n");}

37911067542

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

x

p=x+m

a 数组

60

7

11

5

9

4

7

2

3

i

j

i

j

i

j

ji

j

i

Ch9_71.c

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

Ch9_9.c

Page 30: Ch10    指针

30

第十章 指针例 将数组 a 中的 n 个整数按相反顺序存放

void inv(int x[], int n){ int t,i,j,m=(n-1)/2; for(i=0;i<=m;i++) { j=n-1-i; t=x[i]; x[i]=x[j]; x[j]=t; }}main(){ int i,a[10],*p=a; for(i=0;i<10;i++,p++) scanf("%d",p); p=a; inv(p,10); printf("The array has been reverted:\n"); for(p=arr;p<arr+10;p++) printf("%d ",*p);}

Ch9_72.c

Page 31: Ch10    指针

31

第十章 指针

• 一级指针变量与一维数组的关系int *p 与 int q[10]

– 数组名是指针(地址)常量– p=q; p+i 是 q[i] 的地址– 数组元素的表示方法 : 下标法和指针法, 即若 p=q,

则 p[i] q[i] *(p+i) *(q+i)

– 形参数组实质上是指针变量,即 int q[ ] int *q– 在定义指针变量(不是形参)时,不能把 int *p 写成 int p[];

– 系统只给 p 分配能保存一个指针值的内存区 ( 一般 2 字节);而给 q 分配 2*10 字节的内存区

Page 32: Ch10    指针

32

第十章 指针– 指针与二维数组

• 二维数组的地址

对于一维数组 :

( 1 )数组名 array 表示数组的首地址,即 array[0] 的地址;( 2 )数组名 array 是地址常量( 3 ) array+i 是元素 array[i] 的地址( 4 ) array[i] *(array+i)

array int array[10];

Page 33: Ch10    指针

33

第十章 指针

对于二维数组:( 1 ) a 是数组名, 包含三个元素 a[0],a[1],a[2]

( 2 )每个元素 a[i] 又是一个一维 数组,包含 4 个 元素

a

a+1

a+2

*(*(a+0)+1)

*(a[0]+1)int a[3][4];

a[0]

a[1]

a[2]

2000

2008

2016

2000

2002

2008

2010

2016

2018

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[0]+1

a[1]+1

a[2]+1

*(a+0)+1

*(a+1)+1

*(a+2)+1

Page 34: Ch10    指针

34

第十章 指针– 对二维数组 int a[3][4], 有

» a----- 二维数组的首地址,即第 0 行的首地址» a+i----- 第 i 行的首地址» a[i] *(a+i)------ 第 i 行第 0 列的元素地址» a[i]+j *(a+i)+j ----- 第 i 行第 j 列的元素地址» *(a[i]+j) *(*(a+i)+j) a[i][j]

– a+i=&a[i]=a[i]=*(a+i) =&a[i][0], 值相等,含义不同

» a+i &a[i], 表示第 i 行首地址,指向行» a[i] *(a+i) &a[i][0] ,表示第 i 行第 0 列元

素地址,指向列

int a[3][4];

a[0]

a[1]

a[2]

2000

2008

2016

2000

2002

2008

2010

2016

2018

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

Page 35: Ch10    指针

35

第十章 指针

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]

二维数组元素表示形式:( 1 ) a[1][2]( 2 ) *(a[1]+2)( 3 ) *(*(a+1)+2)( 4 ) *(&a[0][0]+1*4+2)

地址表示:(1) a+1 (2) &a[1][0](3) a[1](4) *(a+1)(5)(int *) (a+1)

行指针

列指针

地址表示:(1) &a[1][2](2) a[1]+2(3) *(a+1)+2(4)&a[0][0]+1*4+2

Page 36: Ch10    指针

36

第十章 指针

表示形式 含义 地址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

13

Page 37: Ch10    指针

37

第十章 指针• 二维数组的指针变量

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

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); }}

p=*a; p=&a[0][0]; p=*(a+0); p=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]

pCh9_12.c

Page 38: Ch10    指针

38

第十章 指针– 指向一维数组的指针变量

» 定义形式: 数据类型 (* 指针名 )[ 一维数组维数 ]; 例 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 39: Ch10    指针

39

第十章 指针例 一维数组指针变量举例

main(){ static int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int i,j,(*p)[4]; for(p=a,i=0;i<3;i++,p++) for(j=0;j<4;j++) printf("%d ",*(*p+j));

printf("\n");

} p=a[0]; p=*a; p=&a[0][0]; p=&a[0];

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

p

p

p[0][j]

Ch9_13.c

Page 40: Ch10    指针

40

第十章 指针

例 二维数组与指针运算

main(){ int a[3][4]={{1,2,3,4},{3,4,5,6},{5,6,7,8}}; int i; int (*p)[4]=a,*q=a[0]; for(i=0;i<3;i++) { if(i==0)

(*p)[i+i/2]=*q+1;else p++,++q;

} for(i=0;i<3;i++) printf("%d,",a[i][i]); printf("%d,%d\n",*((int *)p),*q);}

运行结果: 2,4,7,5,3

1 2 3 4

3 4 5 6

5 6 7 8

p

q

2p

q

p

q

Ch9_06.c

Page 41: Ch10    指针

41

第十章 指针• 二维数组的指针作函数参数

– 用指向变量的指针变量– 用指向一维数组的指针变量– 用二维数组名

实参 形参数组名 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 42: Ch10    指针

42

第十章 指针例 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 (*q)[4], int n){ int i; printf(" No.%d :\n",n); for(i=0;i<4;i++) printf("%5.2f ",*(*(q+n)+i));}

列指针

行指针

函数说明

float p[][4]

65 52 79 60

80 87 90 81

90 99 100 98

q

p

q[n][i]

Ch9_14.c

Page 43: Ch10    指针

43

第十章 指针

Ch9_15.c

例 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 52 79 60

80 87 90 81

90 99 100 98

p

p[j][i]

Page 44: Ch10    指针

44

第十章 指针» 二维数组与一维数组指针变量的关系 如 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 45: Ch10    指针

45

第十章 指针

• 10.4 指针与字符串– 字符串表示形式

• 用字符数组实现例 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 46: Ch10    指针

46

第十章 指针• 用字符指针实现

例 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

Ch9_17.c

Page 47: Ch10    指针

47

第十章 指针– 字符串指针作函数参数

例 用函数调用实现字符串复制

( 1 )用字符数组作参数

( 2 )用字符指针变量作参数

aI

am

a

teac

eh

\0

r.

froma

by

u

ar

a

s

ut

n

de

tob

o

e

t.

\0

I

a

a

e

c

eh

\0

r.

t.

\0

m

t

a

void copy_string(char from[],char to[]){ int i=0; while(from[i]!='\0') { to[i]=from[i];

i++; } to[i]='\0';}main(){ char a[]="I am a teacher."; char b[]="You are a student."; printf("string_a=%s\n string_b=%s\n",a,b); copy_string(a,b); printf("\nstring_a=%s\nstring_b=%s\n",a,b);}

void copy_string(char *from,char *to){ for(;*from!='\0';from++,to++) *to=*from; *to='\0';}main(){ char *a="I am a teacher."; char *b="You are a student."; printf("string_a=%s\nstring_b=%s\n",a,b); copy_string(a,b); printf("\nstring_a=%s\nstring_b=%s\n",a,b);}

Ch9_201.c

Ch9_20.c

Page 48: Ch10    指针

48

第十章 指针– 字符指针变量与字符数组

char *cp; 与 char str[20];

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

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

• char str[20]; str=“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 49: Ch10    指针

49

第十章 指针字符串与数组关系

– 字符串用一维字符数组存放– 字符数组具有一维数组的所有特点

» 数组名是指向数组首地址的地址常量» 数组元素的引用方法可用指针法和下标法» 数组名作函数参数是地址传递等

– 区别» 存储格式:字符串结束标志» 赋值方式与初始化» 输入输出方式: %s %c

char str[]={“Hello!”}; ()char str[]=“Hello!”; ()char str[]={‘H’,‘e’,‘l’,‘l’,‘o’,‘!’}; ()char *cp=“Hello”; ()int a[]={1,2,3,4,5}; ()int *p={1,2,3,4,5}; ()

char str[10],*cp;int a[10],*p;str=“Hello”; ()cp=“Hello!”; ()a={1,2,3,4,5}; ()p={1,2,3,4,5}; ()

scanf(“%s”,str);printf(“%s”,str);gets(str);puts(str);

Page 50: Ch10    指针

50

第十章 指针

• 10.5 指针与函数– 函数指针:函数在编译时被分配的入口地址 , 用

函数名表示 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 51: Ch10    指针

51

第十章 指针例 用函数指针变量调用函数,比较两个数大小

main(){ int max(int ,int); int a,b,c; scanf("%d,%d",&a,&b); c=max(a,b); printf("a=%d,b=%d,max=%d\n",a,b,c);} int max(int x,int y){ int z; if(x>y) z=x; else z=y; return(z);}

main(){ int max(int ,int), (*p)(); int a,b,c; p=max; scanf("%d,%d",&a,&b); c=(*p)(a,b); printf("a=%d,b=%d,max=%d\n",a,b,c);}int max(int x,int y){ int z; if(x>y) z=x; else z=y; return(z);}

Ch9_23.c

Page 52: Ch10    指针

52

第十章 指针– 用函数指针变量作函数参数

例 用函数指针变量作参数,求最大值、最小值和两数之和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);}

Ch9_24.c

Page 53: Ch10    指针

53

第十章 指针• 10.6 返回指针值的函数

– 函数定义形式: 类型标识符 * 函数名 ( 参数表 );例 int *f(int x, int y)

例 : 指针函数实现:有若干学生成绩,要求输入学生序号后, 能输出其全部成绩 .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

Ch9_26.c

Page 54: Ch10    指针

54

第十章 指针例 写一个函数,求两个 int 型变量中居于较大值的变量的地址

int *f1(int *x,int *y){ if(*x>*y)

return x; else

return y;}

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

….

..

2000

2008

200A

2002

2004

2006

23

指针变量 y

指针变量 x(f1)

20022000

COPY

变量 a

变量 b

(main)

指针变量 p**

Ch9_009.c

2002

Page 55: Ch10    指针

55

第十章 指针• 10.7 指针数组和多级指针

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

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

明 ] ;例 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 56: Ch10    指针

56

第十章 指针• 指针数组赋值与初始化

L i s p \0

F o r t r a n \0

B a s i c \0

p[0]

p[1]

p[2]

p[3] 0

赋值 :main(){ char a[]="Fortran"; char b[]="Lisp"; char c[]="Basic"; char *p[4]; p[0]=a; p[1]=b; p[2]=c; p[3]=NULL; ……..}

或 :main(){ char *p[4]; p[0]= "Fortran"; p[1]= "Lisp"; p[2]= "Basic"; p[3]=NULL; ……..}

初始化 :main(){ char *p[]={"Fortran", "Lisp", "Basic",NULL}; ……..}

L i s p \0

F o r t r a n \0

B a s i c \0

p[0]

p[1]

p[2]

p[3] 0

Page 57: Ch10    指针

57

第十章 指针

char name[5][9]={“gain”,“much”,“stronger”, “point”,“bye”};

char *name[5]={“gain”,“much”,“stronger”, “point”,“bye”};

g a i n \0

s t r o n g e r \0

p o i n t \0

m u c h \0

name[0]

name[1]

name[2]

name[3]

name[4]b y e \0

g a i n \0

s t r o n g e r \0

p o i n t \0

m u c h \0

b y e \0

• 二维数组与指针数组区别:

二维数组存储空间固定 ;字符指针数组相当于可变列长的二维数组 ;分配内存单元 = 数组维数 *2+各字符串长度 ;

指针数组元素的作用相当于二维数组的行名 ;但指针数组中元素是指针变量 ;二维数组的行名是地址常量 ;

Page 58: Ch10    指针

58

第十章 指针

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]);}

例 : 用指针数组处理二维数组

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

Ch9_281.c

Page 59: Ch10    指针

59

第十章 指针例 对字符串排序(简单选择排序)main(){ void sort(char *name[],int n), print(char *name[],int n); char *name[]={"Follow me","BASIC", "Great Wall","FORTRAN","Computer "}; int n=5; sort(name,n); print(name,n);}void sort(char *name[],int n){ char *temp; 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) { temp=name[i]; name[i]=name[k]; name[k]=temp;} }}

name[0]

name[1]

name[2]

name[3]

name[4]

name

Great Wall

FORTRAN

Computer

Follow me

BASIC

k

jk

jj

j

i=0

Ch9_28.c

Page 60: Ch10    指针

60

第十章 指针

例 对字符串排序(简单选择排序)main(){ void sort(char *name[],int n), print(char *name[],int n); char *name[]={"Follow me","BASIC", "Great Wall","FORTRAN","Computer "}; int n=5; sort(name,n); print(name,n);}void sort(char *name[],int n){ char *temp; 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) { temp=name[i]; name[i]=name[k]; name[k]=temp;} }}

name[0]

name[1]

name[2]

name[3]

name[4]

name

Great Wall

FORTRAN

Computer

Follow me

BASICk

kjj

j

i=1

k

Ch9_28.c

Page 61: Ch10    指针

61

第十章 指针

例 对字符串排序(简单选择排序)main(){ void sort(char *name[],int n), print(char *name[],int n); char *name[]={"Follow me","BASIC", "Great Wall","FORTRAN","Computer "}; int n=5; sort(name,n); print(name,n);}void sort(char *name[],int n){ char *temp; 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) { temp=name[i]; name[i]=name[k]; name[k]=temp;} }}

name[0]

name[1]

name[2]

name[3]

name[4]

name

Great Wall

FORTRAN

Computer

Follow me

BASICk

k j

j

i=2

Ch9_28.c

Page 62: Ch10    指针

62

第十章 指针

例 对字符串排序(简单选择排序)main(){ void sort(char *name[],int n), print(char *name[],int n); char *name[]={"Follow me","BASIC", "Great Wall","FORTRAN","Computer "}; int n=5; sort(name,n); print(name,n);}void sort(char *name[],int n){ char *temp; 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) { temp=name[i]; name[i]=name[k]; name[k]=temp;} }}

name[0]

name[1]

name[2]

name[3]

name[4]

name

Great Wall

FORTRAN

Computer

Follow me

BASIC

k

j

i=3

Ch9_28.c

Page 63: Ch10    指针

63

第十章 指针

例 对字符串排序(简单选择排序)main(){ void sort(char *name[],int n), print(char *name[],int n); char *name[]={"Follow me","BASIC", "Great Wall","FORTRAN","Computer "}; int n=5; sort(name,n); print(name,n);}void sort(char *name[],int n){ char *temp; 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) { temp=name[i]; name[i]=name[k]; name[k]=temp;} }}

name[0]

name[1]

name[2]

name[3]

name[4]

name

Great Wall

FORTRAN

Computer

Follow me

BASIC

Ch9_28.c

Page 64: Ch10    指针

64

第十章 指针– 多级指针

• 定义 : 指向指针的指针• 一级指针 : 指针变量中存放目标变量的地址

p1

&p2 &i 3

P2( 指针变量 ) i( 整型变量 )例 int **p1; int *p2; int i=3; p2=&i; p1=&p2; **p1=5;

• 二级指针 : 指针变量中存放一级指针变量的地址

例 int *p; int i=3; p=&i; *p=5;

&i 3

P( 指针变量 ) i( 整型变量 )

一级指针 单级间接寻址

二级指针 一级指针 目标变量

二级间接寻址

Page 65: Ch10    指针

65

第十章 指针– 定义形式: [ 存储类型 ] 数据类型 ** 指针名;如 char **p;

例 int i, **p; p=&i; //p 是二级指针,不能用变量地址为其赋值

指针本身的存储类型最终目标变量的数据类型*p是 p间接指向对象的地址**p 是 p间接指向对象的值例 int i=3;

int *p1; int **p2; p1=&i; p2=&p1; **p=5;

ip1

p2

3&i

&p1

**p2, *p1

*p2

• 多级指针

例 三级指针 int ***p; 四级指针 char ****p;

Page 66: Ch10    指针

66

第十章 指针例 用二级指针处理字符串

#define NULL 0void main(){ char **p; char *name[]={"hello","good","world","bye",""}; p=name+1; printf("%o : %s ", *p,*p); p+=2; while(**p!=NULL) printf("%s\n",*p++);}

name[0]

name[1]

name[2]

name[3]

name[4]

char *name[5]

world

bye

\0

hello

good

name

p

运行结果:644 : good bye

用 *p 可输出地址 (%o 或 %x), 也可用它输出字符串 (%s)

p*(p++)

Ch9_000.c

Page 67: Ch10    指针

67

第十章 指针

• 二级指针与指针数组的关系int **p 与 int *q[10]

– 指针数组名是二级指针常量– p=q; p+i 是 q[i] 的地址– 指针数组作形参, int *q[ ] 与 int **q完全等价;但作为变量定

义两者不同– 系统只给 p 分配能保存一个指针值的内存区;而给 q 分配 10块

内存区,每块可保存一个指针值

Page 68: Ch10    指针

68

第十章 指针– 命令行参数

• 命令行:在操作系统状态下,为执行某个程序而键入的一行字符

• 命令行一般形式:命令名 参数 1 参数 2……… 参数n

main(int argc, char *argv[]){ ………}

• 命令行参数传递

• 带参数的 main 函数形式:C:\TC> copy[.exe] source.c temp.c

有 3 个字符串参数的命令行

命令行中参数个数 元素指向命令行参数中各字符串首地址

形参名任意

命令行实参 main( 形参 )

系统自动调用main 函数时传递

第一个参数 : main 所在的可执行文件名

Page 69: Ch10    指针

69

第十章 指针例 输出命令行参数

/*test.c*/main(int argc, char *argv[]){ while(argc>1) { ++argv; printf("%s\n",*argv); --argc; }}

main(int argc, char *argv[]){ while(argc-->0) printf("%s\n",*argv++);}

1. 编译、链接 test.c ,生成可执行文件 test.exe2. 在 DOS 状态下运行 (test.exe 所在路径下)

例如: C:\TC> test[.exe] hello world!

运行结果: hello world!

运行结果: test hello world!

argv[0]

argv[1]

argv[2]

char *argv[]

world

test

hello

argv

argc=3

Ch9_311.c

Page 70: Ch10    指针

70

第十章 指针

定义 含义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 71: Ch10    指针

71

第十章 指针

例 下列定义的含义( 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 型变量