第 10 章 指 针
DESCRIPTION
第 10 章 指 针. 指针是C语言中的重要概念,也是C语言的重要特色。使用指针,可以使程序更加简洁、紧凑、高效。. §10.1 指针的概念. 一 . 内存单元的内容、内存单元地址 : 内存区域划分为一个一个的内存单元,一个内存单元 可以存放一字节数据,每一个内存单元都有一个地址。 例: int i=3 ; char j=‘s’;. 地址. 内存单元. 3. 2002 2004 3000. 2000 2001. 变量 i 变量 j. 编译时为变量 i 分配 2000 和 2001 两 - PowerPoint PPT PresentationTRANSCRIPT
第 10 章 指 针 指针是C语言中的重指针是C语言中的重要概念,也是C语言的重要概念,也是C语言的重要特色。使用指针,可以要特色。使用指针,可以使程序更加简洁、紧凑、使程序更加简洁、紧凑、高效。高效。
§10.1 指针的概念 一 . 内存单元的内容、内存单元地址: 内存区域划分为一个一个的内存单元,一个内存单元 可以存放一字节数据,每一个内存单元都有一个地址。 例: int i=3 ;
char j=‘s’; 变量 i
变量 j
编译时为变量 i 分配 2000 和 2001 两个字节的内存单元 , 为 j 分配 2003一个字节的内存单元
2002
2004
3000
20002001
2003
地址
75
2003
内存单元
通常把内存单元的地址称为指针 .
指针变量 j-pointer
3
二 .内存单元的访问: 直接访问:通过变量名访问。 char j=‘s’;
printf(“%c”, j );
间接访问:通过该变量的指针来访问。 p=&j;
称:指针变量 p 指向变量 j ,是变量 j 的指针。
752000j
752000
jp
指针( pointer ):是一个变量的地址 ,
是常量。
指针变量:是指取值为地址的变量,其 值是另一个变量的地址。
要引用指针 , 必须定义指针。 定义指针 , 是为了通过指针访问内存单元。 一个数组或函数占有一段连续内存单元 , 假如将
一个数组或函数的首地址赋给指针变量 , 通过指针就可以找到数组或函数。
§10.2 变量的指针一、指针变量的定义 类型标识符 * 标识符
例如: int *cm “ 标识符”是指针变量名 “*” 表示定义指针变量 “ 类型标识符”表示该指针变量所指向的变量
类型。 指针是一个变量的地址 , 为了表示指针与它指
向变量的地址之间的关系 , 用 * 表示指向 .
二、指针变量的引用 未经赋值的指针变量不能用。 指针变量只能赋予地址。 C 语言提供两种相关地址运算符: &: 取地址运算符 *: 取内容运算符 * \ & 优先级相同 .
例 : int a=5,b; int *p; p=&a; b=*p;
类型说明中的 * 表示定义指针变量
表达式中的 * 是运算符
52000 a
2002 b
......
3000 p
2000 &a
&a 5
p a
三、指针变量的赋值 :(1) 、 int a,*pa ; pa=&a; (2) 、 int a=5,*p=&a;(3) 、 int a,*pa=&a,*pb; pb=pa;
(4) 、 int a[5],*pa; pa=a; (5) 、 char *pc ; pc=“c language” ;
/* 整型变量 a 的地址赋给指针变量 pa*/
/* 指针变量 p 取得整型变量 a 的地址 .*/
/* 指针 pa 的值赋给指针 pb*/
/* 将数组的首地址赋给相同类型的指针 */
/* 将字符串的首地址赋给指针变量 */
[ 例 10.1] main () { int a,b; int *pointer_1, *pointer_2; /* 定义指针变量 */ a = 100; b = 10; pointer_1 = &a; pointer_2 = &b; printf("%d,%d\n", a,b ); printf("%d,%d\n", *pointer_1,*pointer_2 ); } 程序运行结果:
&a
&b
100
10
pointer-1
pointer-2
a
b
100 , 10 100 , 10
[ 例 10.2] 输入 a 和 b 两个整数,按先大后小的顺序输出 a 和 b 。 See:9_2.c 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 ); } 运行 :5,9
&a 5
p1 a
&b 9
p2 b
p
a=5,b=9; max=9,min=5该例不交换变量 a 、 b 的值,而是交换指针 p1 、 p2 的值。
&b
&a
四、指针变量作为函数的参数[ 例 10.3] 题目要求同 [ 例 10.2] ,输入 a 和 b 两个整数,按先大
后小的顺序输出 a 和 b 。 swap( int* p1,int *p2 ) /* 交换指针 p1 、 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); } 把变量 a 和 b 的地址传送给形参
§10.3 数组的指针 指针可以指向数组和数组元素 , 对数组元素的访问 :
既可以使用数组下标 , 也可以使用指针 .
一、指向数组元素的指针变量 指向数组元素的指针变量,其类型应与数组元素相同 .
例 1: int a[7]; int *pa; pa=&a[0]; 或 pa=a; 例 2: float b[10],*pb=b ; 或 float b[10],pb=&b[0];
1
2
3
4
5
6
7
&a[0]pa a[0]
a[6]
二、通过指针引用数组元素 设 :int a[10],*p=&a[0]; (1).p+1 和 a+1 指向下一个元素 a[1];
如果数组元素是整型, p+1 表示 p 的地址加 2 ;如果数组元素是实型, p+1 表示 p 的地址加 4 ;
p+i 和 a+i 指向元素 a[i] 。(2).*(p+i) 和 *(a+i) 访问元素 a[i];
例 : *(p+5) 和 *(a+5) 与 a[5] 等效 ;
(3). 指向数组指针可以带下标 :
例 : p[i] 与 *(p+i) 等效 .
[ 例 10.5] 输出数组的全部元素。(设 10 个元素,整型)。
访问各元素有三种方法: 1 、下标法(常用,很直观) main () { int a[10]; int i; for(i=0;i<10;i++) scanf("%d", &a[i]); printf("\n"); for(i=0;i<10;i++) printf("%d ", a[i] ); }
2 、用数组名计算数组元素的地址。 (效率与下标法相同,常用) main ()
{
int a[10];
int i;
for(i=0;i<10;i++)
scanf("%d", &a[i]);
printf("\n");
for(i=0;i<10;i++)
printf("%d ", *(a+i) );
}
特点 : 不移动指针
3 、用指针访问各元素。(常用,效率高) main () (see:9_5.c)
{
int a[10];
int *p , i;
for(i=0;i<10;i++)
scanf("%d", &a[i]);
printf("\n");
for( p=a ; p<(a+10) ; p++ ) /* p++ 使 p 指向下一个元素 */
printf("%d ", *p );
}
特点 : 移动执针
例:通过以下程序输出 a 数组中的 10 个元素。
main(){
int a[10],*p,i;p=a;for(i=0;i<10;i++)
scanf("%d",p++);printf("\n");for(i=0;i<10;i++,p++)
printf("%d\t",*p);}
??请问大家:以上程序可以输出a 数组中的 10 个元素吗?
三、数组名作函数参数1 、形参和实参都用数组名
例 :main()
{int array[10];
…
f(array,10);
…
}
f( int arr[ ],int n)
{
…
}
例 :main()
{int array[10];
…
f(array,10);
…
}
f( int *arr,int n)
{
…
}
2 、实参用数组名,形参用指针变量。
例 :main()
{int array[10] , *p;
p=array;
…
f(p,10);
…
}
f( int *arr,int n)
{
…
}
3 、实参、形参都用指针变量。
例 :main()
{int array[10] , *p;
p=array;
…
f(p,10);
…
}
f( int arr[ ],int n)
{
…
}
4 、实参用指针变量,形参用数组名 。
实际上 ,c 编译系统将形参数组名作为指针变量处理 .
若有定义 :f(int arr[ ],int n)
编译后 :f(int *arr,int n)
§10.4 字符串的指针一、字符串的表现形式 C 语言中,有两种方式可以实现字符串: 字符数组、字符指针。 [ 例 10.16] :字符数组 main()
{ char string[ ] ={"I love China!”};
printf("%s\n",string);
} string 是数组名,代表字符数组的首地址。数组可以用下标访问,也可以用指针访问
用字符串对字符数组赋值
[ 例 10.17] 字符指针 main()
{ char *name1 =”Mary";
char *name2=“Hare”;
printf("%s%s\n",name1,name2);
}
name1 是一个指针变量
char *name1 =“Mary”; 等价于 : char * name1; name1 = ”Mary";它把字符串常量的首地址赋给指针 name1.
name1
name2
Mary
Hare
[ 例 10.18] 将字符串 a 复制到字符串 b 。main () { char a[ ] = "I am a boy."; char b[20]; int i; for (i=0; *(a+i) !='\0'; i++) *(b+i) = *(a+i); *(b+i) = '\0'; printf("string a is: %s\n",a); printf("string b is:"); for (i=0; b[i] !='\0'; i++) printf("%c",b[i]); printf("\n"); }
I
am
数组 a
a
a
boy.
\0
数组 b b
用数组名计算数组元素的地址
特点 : 不移动指针
[ 例 10.19]: 用指针处理字串复制 .main () { char a[ ] = "I am a boy.",b[20],*p1,*p2; int i; p1=a;p2=b; for ( ; *p1 !='\0'; p1++,p2++) *p2 = *p1; *p2 = '\0'; printf("string a is: %s\n",a); printf("string b is:"); for (i=0; b[i] !='\0'; i++) printf("%c",b[i]); printf("\n"); }
I
am
数组 ap1
a
boy.
\0
数组b
p2
特点 : 移动执针
I
am
a
boy.\0
例 10.21: main() { char *a=“I love china!”; a=a+7; printf(“%s”,a); } 运行结果如下 : China!
(a+7) 是用指针指向数组元素 a[i] 的第 7 个字符
§10.5 函数指针一、用函数指针变量调用函数 函数指针定义的一般形式: 函数返回值类型( * 指针变量名)( )
例 : int (*p) ( )
◆ 说明:( *p ) ( ) 表示定义一个指向函数的指针变量,它不固定指向哪一个函数,它是专门用来存放函数的入口地址的,该函数返回一个整型值 . 。
C 规定 : 函数的名称就是函数的入口地址
[ 例 9.23] 求 a 和 b 中的大者。 用函数名调用函数 max() int max(int x, int y); /* 原型 */ {int z; if (x>y) z = x; else z = y; return z; }
main () {int a,b,c; scanf("%d,%d", &a, &b); c = max(a, b); printf("a=%d,b=%d,max=%d",a,b,c); }
用函数指针调用函数 max() int max(int x, int y) /* 原型 */ {int z; if (x>y) z = x; else z = y; return z;} main () { int (*p) ( );/* 定义函数指针 p */
int a,b,c; p = max; /* 函数 max 的入口地址赋给函数指针 p
*/ scanf("%d,%d", &a, &b); c = (*p)(a,b); /* 用函数指针 p 调用函数 */
printf("a=%d,b=%d,max=%d",a,b,c);}
用函数指针变量调用函数时,只须将(*p) 代替函数名 max ,并加上实参
§10.6 返回指针的函数 ( 自学 )一般形式: 类型标识符 * 函数名(参数表)例、 int * a (int x, int y) 声明一个函数,函数名为 a ,其返回值类型是
“指向整型的指针”, 函数形式参数为 int x 和 int y 。
注意 : 在 a 的两侧分别为 * 运算符和 ( ) 运算符 ,a 先与 ( )结合 , 这是函数形式 ; 函数前有个 * 号 , 表示该函数为指针型函数 .
§10.7 指针数组和指向指针的指针( 自学 )
一、指针数组概念:指针数组是一个数组,该数组中的 每一个元素是指针变量。形式:类型标识符 * 数组名[数组元素个数]
例: int * p[4]; 定义一个指针数组,数组名 p ,有 4 个元素, 每一个元素
是指向整型变量的指针。
二、指向指针的指针 定义举例: char * * p;
char *name[]={“Ann”,“Hare”,“Jack”};
p=name;
p 是一个指向指针的指针 . 被 p 指向的指针指向字符变量。
name[0]
name[1]
name[2]
Ann
Hare
Jack
p
二维字符数组name 指针数组
main() {int i; char *name[]={"Ann","Hare","Jack","Mary"}; /* storage address of per string*/
char **p; printf("\n Students's names are:\n"); for(i=0;i<4;i++) { p=name+i; /*point into address of next char string */
printf("%6s\t",*p); } }
运行结果 : Ann Hare Jack Mary
name[0]
name[1]
name[2]
Ann
Hare
Jack
p
二维字符数组name 指针数组
name[3] mary
§10.8 指针使用小结一、有关指针的数据类型定义 : int i; 定义整型变量 i
int *p; p 是指向整型数据的指针变量 int a[n]; 定义数组 a ,元素类型为 int ,元素个数是 n int *p[n]; p 是指针数组 , 包含 n 个指针 , 每一个指针可以指向整型数据
int f( ); f 是函数,返回值是 int int (*p)( ); p 是函数指针,所指向的函数返回整型数据 int *p( ); p 是函数,返回值是指针,该指针指向整型数据 int **p; p 是指针,指向一个指向整型数据的指针
二、指针运算小结
1 、指针变量加 / 减运算 p++ 、 p-- 、 p+i 、 p-i 、 p+=i 、 p-=i 加 1 表示指向下一个数据。2 、指针变量赋值 p = &a; 变量 a 的地址赋给 p ,即指针 p 指向 a
p = array; 数组 array 首地址赋给 p
p = &array[i]; 数组元素 array[i] 的地址赋给 p p = max; 函数 max 的入口地址赋给 p
p1 = p2; 指针 p2 的值赋给指针 p1 , 即 p1 、 p2 所指的数据相同 p=NULL; 指针变量可以由空值 ,NULL 的值为 0
3 、空指针 p = NULL 空指针 p=NULL 表示 p 不指向任何数据。 在 stdio.h 中, NULL 被定义为 0 : #define NULL 0
习惯上,不使用 p = 0 而使用 p = NULL 指针变量 p 可以与 NULL 作比较,例 : if (p = = NULL) ...
注意:空指针不指向任何数据,与 p 未赋值不同。 当 p 未赋值时,其值是不确定的,而空指针 的值是确定数 0 。
4、指针变量相减。 当 p1 、 p2 指向同一个数组的元素,指针相减 p2-
p1 等于 p1 、 p2 间的元素个数。 注意:指针相加无意义。
5 、两个指针的比较 当 p1 、 p2 指向同一个数组的元素时,可以比较,
如、 p1 > p2 。若 p1 、 p2 不是指向同一个数组的元素,比较无意义。
三、空类型指针 void * void *p ,表示 p 是空类型指针,它可以指向任何数
据类型。 空类型指针与其他类型指针之间赋值时,应进行强制
类型转换 .
例、 char *p1; void *p2; p1 = (char *)p2; p2 = (void *)p1;
第 10 章 习 题10.1 指针变量 a 所指的字符串长度为 , 这个长度是可以用 strlen(a) 测出来的。 char *a=“\nMY Name is\”zhang li\”.\n”; (1)28 (2) 27 (3) 26 (4) 24 (5)2310.2 下面程序的作用是,将两个变量中的值互换, 请检查程序是否正确,如不正确的,改正之。 main ( ) {int a=3,b=4; int *p1,*p2,*p; p1=&a,p2=&b; p=p1;p1=p2;p2=p; printf(“a= %d,b= %d\n”,a,b); }
*p1,*p2
10.3 已设 p1 和 p2 为指针变量,且已指向同一个整 型数组中的元素, a 是一个整型变量,问下面 哪一个语句不能正确执行 ? (1) a=*p1 (2) a=*p1+*p2 (3) a=*p1-*p2 (4) p1=a-p210.4 有一个二维数组 a[3,4],2 行 3列元素的正确表 示方法为 。 (1) &a[2][3] (2)a[2]+3 (3) *(a+2)+3 (4)*(a[2]+3)10.5 下列程序的输出结果是 A)44 B)22 C)24 D) 结果错误 main()
{int a[5]={2,4,6,8,10},*p,**k;
p=a;k=&p;
printf("%d",*(p));
printf("%d\n",**k);
}
10.6 若有语句 :int a=4,*p=&a;
下面均代表地址的一组选项是 : 1) a,p,&*a 2) *&a,&a,*p
3) &a,p,&*p 4) *&p,*p,&a
10.7 以下程序段的输出结果为 :
char a[]=“Program”,*ptr;
ptr =a;
for ( ;ptr<a+7;ptr+=2)putchar(*ptr);
1) Program 2) Porm
3) 有语法错误 ; 4) Por
10.8 下面说明不正确的是 :
1) int *a[4]; 2) float (*p)();
2) int **p; 4) char *(*a)[];
作业 10.1 10.2 10.6 10.11
上机实验 学生成绩管理 ( 使用指针 ):
1. 学生姓名与成绩录入 ;
2. 求学生平均成绩并输出 ;
3. 将不及格的学生姓名与成绩输出 ;
4. 按从高到低成绩排序并输出 .