C语言程序设计
2002 年第 七 章 指 针
7.1 指针的概念与指针的使用一,指针的概念
数据(变量、常量)(根据类型)占有一定数目的连续存储单元;
数据的连续存储单元首地址称为 数据的地址 。
程序中能操作变量、常量的地址;
char c; &c为变量 c的地址。
const int NUM=10; &NUM为常量 NUM的地址。
变量的地址称为 指针,存放地址数据的变量称为 指针变量 。
&c?a?
pc c
执行赋值操作 pc=&c后,称 pc指向 c,或 pc是 c的指针 ;
变量 c称为 pc的指向 。
二,指针说明存储类型区分符 类型区分符 *标识符,…… ;
其中,*标识符 称为指针说明符。
例,char c,*pc;
float f,*pf;
int i,*pi;
pc=&c; pf=&f; pi=&i;
&c
pc c
&f
pf f
&i
pi i
常见的复杂说明:
int *pi; /*整型数的指针变量,被指向的是一 个整型数 */
int (*pa)[5]; /*指针变量,被指向的是一 个 长度为 5的整型数组 */
int *a[10]; /*长度为 10的指针数组,每一个元素都是整型指针 */
int *fpi(void); /*函数 fpi的说明,fpi的返回值为整型指针 */
int (*pfi)(char *); /*函数指针说明,pfi在不同时刻可指向不同的函数入口,被指向的函数形参为字符指针,返回值为整型 */
int *(*pfpi)(int); /*函数指针说明,pfi在不同时刻可指向 不同的函数入口,被指向的函数形参为整型,返回值为整型指针 */
三、指针的使用
1。指针运算符单目 & 取地址运算符
&与操作数组成的表达式称为地址表达式。该类表达式的运算结果为操作数变量的地址。形式为:
&操作数 (注:数组名也是地址表达式)
操作数必须为左值表达式(变量和有名称的存储区)
例,int i,a[10];
const int NUM=10;
地址表达式,&i &a[0] &NUM
a
单目 * 间接访问运算符通过指针间接访问指针所指向的对象。
例,int a=10; /*直接写 */
int *p=&a; /*建立指向关系 */
printf(“%d”,a); /*直接接读 */
printf(“%d”,*p); /*间接读 */
*p=20; /*间接写 */
printf(“%d”,a);
printf(“%d”,*p);
单目 *和 &的互为逆运算:
*(&a) 的值为 a的值。
&a
p a
1 0
&a
p a
2 0
2。指针的正确用法使用指针的目的,是给变量提供间接的操作,完成直接通过变量名不能完成的操作,实现跨变量的作用域对变量实施存取访问。
定义、使用方法步骤:
( 1)根据指针所指向数据的数据类型,定义指针变量;
int a=10,b=20;
int *pa,*pb;
( 2)建立指针和被指向数据的关系;
pa=&a; pb=&b;
( 3)使用指针对被指向数据进行操作。
printf(“%d %d”,*pa,*pb;);
注,由于 pa和 pb是变量,不同时刻可指向不同数据;
例如,pa=&a; pb=&b; 所以使用时,必须清楚指针当前的指向。
3。 void指针和 NULL指针
void指针是类型为 void *的指针;( 空类型指针 )
void *的指针是一种通用指针类型。表示该指针指向不定类型。
任何指针变量都可赋予整数 0(一个特殊的指针,空指针 )
C语言用符号常量 NULL表示空指针,
NULL在 stdio.h和 stdlib.h中定义:
#define NULL 0
通常,用 NULL与非 NULL判断某种操作的结果:
void *p; p=malloc(10); 判断 p
char s1[]=“abc”; s2[]=“123”,*pc;
pc=strstr(s1,s2); 判断 pc
7.2 指针的运算
1,算术运算
( 1)指针加、减一个整数
int a[10],*p=&a[4];
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]
a 1000
p+3 表达式的值为 a[7]的地址; 1008+3*sizeof(int)=1014
p-4 表达式的值为 a[0]的地址。 1008-4*sizeof(int)=1000
p 1008
( 2)两个指针相减
int a[10],*p1=&a[2],*p2=&a[7];
int b[6],*p3=&b[4];
float c[5],*p4=&b[3];
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]
a 1000
p2-p1 表达式的值整型数;表示 p1与 p2之间间隔元素的数目。
( 1014-1004) /sizefo(int)=10/2=5
p3-p1 无意义 ; p4-p2 无意义,
p1 1004 p2 1014
2,关系运算被比较的两指针类型必须相同,并且一般两指针指向同一数组中的元素,否则无意义。
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]
a 1000
p == q 表示指向同一元素; p != q 表示指向不同元素;
p < q 表示 p所指向元素位于 q所指向元素之前;
p > q 表示 p所指向元素位于 q所指向元素之后。
空指针 NULL 可与任何类型的指针进行关系运算,
通常作 ==或 !=比较。
p 1008 q 1008
3,赋值运算
( 1) 任一指针可直接赋予同类型的指针变量;
int a=10,*pa=&a,*pb;
pb=pa;
( 2) 不同类型指针赋值时,必须进行类型强制转换;
short *pc; pc=(int *) pa;
( 3)任何类型指针可直接赋给 void指针; void指针和
NULL(整常数 0)指针可直接赋给任何类型指针;
void *pv;
pv=pa; pv=pc;
pb=pv; pc=NULL;
7.3 指针参数
C语言中,需要在被调用函数中修改调用函数中的变量的值时,必须使用指针参数。
一、指针参数的用法例 7.1 交换两个变量的值(方法 1)
void swap(int x,int y);
{ int temp;
temp=x;x=y;y=temp; /*交换的实参 a,b的副本 */
}
main()
{ int a=10,b=20;
swap(a,b);
printf(“a=%d,b=%d”,a,b);
}
temp
y 20x 10
b 20a 10
参数传递参数传递例 7.1 交换两个变量的值(方法 2)
void swap(int *pa,int *pb);
{ int temp;
temp=*pa;*pa=*pb;*pb=temp; /*交换的实参 a,b本身 */
}
main()
{ int a=10,b=20;
swap(&a,&b);
printf(“a=%d,b=%d”,a,b);
}
temp
pb &bpa &a
b 20a 10
参数传递
&a
参数传递
&b
7.4 数组的指针表示
C语言中数组与指针的关系:
( 1)数组名是数组首地址,其类型为数组元素类型的指针常量;
( 2)数组元素可用下标表示,也可以用指针表示,两者可互相替代,也可混合使用;
( 3)编译程序处理 a[i]时,根据 a和 i的值计算 a[i]的地址:
a[i]的含义,a指向的数据后续的第 i个数据,a[0]就是 a指向的数据;
&a[i]=a+i=a+i*数组元素类型的长度
a[i]=*(a+i)
a[i]=*(&a[i])
7.4.1 一维数组的指针表示
1,一维数组的指针表示方法
main()
{ int i,a[10],*pi,s=0;
for(pi=&a[0],i=1;i<=10;i++) /*用指针给数组元素赋值 */
{*pi=i; pi++}
for(pi=&a[0];pi<&a[10];pi++) /*用指针输出数组元素 */
printf(“%6d”,*pi);
for(i=0;i<10;i++)
s+=*(a+i);
}
2,数组参数的指针表示
int max(int *x,int n) /* 等价于 max(int x[],int n) */
{ int index=1,i;
for(i=1;i<n;i++)
if ( *(x+i) > *(x+index)) /* 等价于 x[i]>x[index] */
index=i;
return index;
}
main()
{ int a[10]={10,33,45,23,17,21,38,55,66,98};
printf(“max=%d”,a[max(a,10)]);
}
*(a+0)或 a[0] 10
*(a+1)或 a[1] 33
*(a+2)或 a[2] 45
*(a+3)或 a[3] 23
*(a+4)或 a[4] 17
*(a+5)或 a[5] 21
*(a+6)或 a[6] 38
*(a+7)或 a[7] 55
*(a+8)或 a[8] 66
*(a+9)或 a[9] 98
a x n 10
x[0]或 *(x+0)
x[1]或 *(x+1)
x[2]或 *(x+2)
x[3]或 *(x+3)
x[4]或 *(x+4)
x[5]或 *(x+5)
x[6]或 *(x+6)
x[7]或 *(x+7)
x[8]或 *(x+8)
x[9]或 *(x+9)
a和 x共同对同一连续存储单元进行操作
main
函数
max
函数
7.4.2 字符串表示
1,字符串的表示方法
C语言无字符串类型,但可以表示字符串数据:
( 1)字符串常量;
( 2)字符数组;
( 3)字符指针变量。
后两种可理解为字符串变量,字符串的长度是隐含的,‘ \0?
表示字符串的结尾。
2,字符串变量的操作
( 1)字符串变量的定义与初始化;
char astr[100]=“a string”; /*一维 字符数组表示字符串 */
char *pstr=“a string”; /*字符指针表示字符串 */
a s t r i n g?\0? …

astr[0] astr[1] astr[2] astr[3] astr[4] astr[5] astr[6] astr[7] astr[8] … astr[99]
a s t r i n g?\0?
pstr[0] pstr[1] pstr[2] pstr[3] pstr[4] ptr[5] pstr[6] pstr[7] pstr[8]
pstr:
astr:
( 2)字符串变量的输入;
char astr[20]; /*字符串最大长度 19*/
char *pstr1=“a string”,*pstr2; /*pstr1字符串最大长度 8*/
scanf(“%s”,astr),/*输入字符个数字不能超过符串最大长度
19*/
scanf(“%s”,pstr1); /*输入字符个数字不能超过符串最大长度 8*/
scanf(“%s”,pstr2); /*不安全,pstr2的值未确定,可能指向当前程序不能访问的存储区,
可能 导致死机 */
( 3)字符串变量的赋值;
char astr[20]; /*字符串最大长度 19*/
char *pstr1=“string1”,*pstr2; /*pstr1字符串最大长度 7*/
astr=,It?s a string” /*错误语句,指针常量不能赋值 */
pstr1=“string2”; /*pstr1指向新的存储区域 */
pstr2=,string3”; /*pstr2指向存储 string3”的区域 */
scanf(“%s”,pstr2); /*输入字符串最大长度为 7*/
s t r i n g 1?\0?pstr1:
s t r i n g 2?\0?
s t r i n g 3?\0?pstr2:
3,字符串参数
等同与字符数组作为函数参数;
参数形式,char *形参名 或 char 形参名 [];
例:定义函数 strcat实现 (字符串 1+字符串 2)?字符串 1
void strcat(char *s1,char *s2)
{
while (*s1!=?\0?) s1++; /*将 s1定位于字符串 1的结束标记处 */
while (*s2!=?\0?) /*控制取字符串 2的所有字符 */
{ *s1=*s2; /*取字符串 2的字符赋给字符串 1 */
s1++,s2++;} /*s1取下一空闲字节,s2取下一字符 */
*s1=?\0?; /*给字符串 1的设置结束标记 */
}
T h e?\0?
s1
s2
s t r i n g?\0?
main()
{ char str1[14]=“The”,*str2=“string”;
strcat(str1,str2);
puts(str2);
}
s1
str1 str2
7.4.3 多维数组的指针表示与数组的指针
1.多维数组的处理方法
C语言中,数组的实现方法只有一维的概念,多维数组可以被看成是以下一级数组为元素的一维数组。具体处理方法为:
( 1) n维数组( n≥2)可以逐级分解成 n-1维数组为元素的一维数组;
( 2) n维数组的数组名是指向 n-1维数组的指针,其值为 n维数组的首地址,类型为 n-1维数组类型的指针;
( 3) n维数组的元素是指向 n-1维数组的的元素的指针,其值为 n-1维数组的首地址,类型为 n-1维数组的元素类型的指针。
例,int a[2][3]
a[0]
a[1]
a
a[0][0]
a[0][1]
a[0][2]
a[1][0]
a[1][1]
a[1][2]
a[0][0]
a[0][1]
a[0][2]
a[1][0]
a[1][1]
a[1][2]
a
a+1
7.5 指针数组数组元素是同类型的指针的数组称为 指针数组 。一般用于表示字符串数组。
7.5.1 指针数组的说明及使用说明形式,*标识符 [数组长度 ]
例,int *ps[5];
其中,ps 数组名
ps[0],ps[1],ps[2],ps[3],ps[4] 均为整型指针。
例,char *name[10];
其中,name 数组名
name[0]….name[9] 均为字符指针,可表示不同字符串。
例:显示系统菜单
main()
{ char *pmenu[]=
{“1,插入”,“2,删除”,,3,修改”,
,4,查询”,“5,统计”,“0,退出”,
“输入选择 [0-5]:”};
int i,blank=30,choice=1;
while (choice!=0)
{ clrscr();
printf(“\n\n %*c”,blank,);
printf(“*****系统名称 ****“);
for(i=0; i<7;i++)
{printf(“\n\n %*c”,blank,);
scanf(“%d”,&choice);
switch (choice)
{
case 1,调用插入功能函数; break;
case 2,调用删除功能函数; break;
case 3,调用修改功能函数; break;
case 4,调用查询功能函数; break;
case 5,调用统计功能函数; break;
}
} /*end of while*/
} /*end of main*/
7.5.2 指针的指针
任何变量占有一定数目的连续存储单元,指针变量也不例外;
指针变量的地址或存放指针变量地址的指针变量称为指针的指针或二级指针。
二级指针说明形式,类型名 **标识符
char **pchar;
其中,pchar指针的指针变量名。
char c=?a?,*pc=&c;
pchar=&pc;
printf(“%c%c%c”,c,*pc,**pc);
printf(“%p%p%p”,pc,pchar,&pchar); /*输出三变量地址 */
&c?a?
pc c
&pc
pchar
#include "stdio.h "
#include "string.h"
void strsort(char *lineptr[],int size)
main()
{
int i,n=4;
char *name[]={"Wang tao","Ling ly","Cheng gang","Din
fen"};
strsort(name,n);
for(i=0;i<n;i++)
printf("%s\n",name[i]);
}
void strsort(char *lineptr[],int size)
{ char *temp; int i,j;
for(i=0;i<size-1;i++)
for(j=0;j<size-i-1;j++)
if (strcmp(lineptr[j],lineptr[j+1])>0)
{
temp=lineptr[j];
lineptr[j]=lineptr[j+1];
lineptr[j+1]=temp;
}
}
name[0]
name[1]
name[2]
name[3]
Wang tao
Ling ly
Ding feng
Cheng gang
指针数组
namelineptr
指针变量的指针带参数的 main函数下面程序文件名为,display.c?display.obj?display.exe
#include "stdio.h"
main(int argc,char *argv[])
{
int i;
clrscr();
for(i=0;i<argc;i++)
printf("%s\n",argv[i]);
}
argv[0]
argv[1]
argv[2]
argv[3]
argv[4]
argv[5]
display
what
day
is
today
argv
指针变量的指针
argc
5
DOS 环境执行 display.exe
C>display what day is today