第九讲 指 针.docx
《第九讲 指 针.docx》由会员分享,可在线阅读,更多相关《第九讲 指 针.docx(26页珍藏版)》请在冰豆网上搜索。
第九讲指针
第九章指针
本章要点:
1.掌握指针与指针变量的概念;
2.掌握指针的定义;
3.掌握指针的运算;
4.掌握指向基本类型、数组、字符串、结构体的指针变量,了解函数指针变量;
5.掌握main()函数的命令行参数。
9.1指针概念
变量地址:
变量一定占用一个数据的存储空间,该存储空间的首地址称变量地址。
指针:
一个变量的地址称为该变量的指针。
指针变量:
若一个变量专用于存放另一个变量的地址(指针),则该变量称为指针变量。
若指针变量p的值等于变量x的地址,则说指针变量p指向变量x
直接访问:
按变量地址存取变量值的方式。
间接访问:
将变量i的地址存放在另一内存单元中。
如定义i_pointer为指针变量,i_pointer=&i;
(1)先找到存放i的地址的单元地址(3010,3011);
(2)取出i的地址(2000);
(3)到2000,2001中取出i的值3
9.2变量的指针和指向变量的
指针变量
9.2.1指针变量的定义
指针变量定义的形式:
类型标识符*标识符
例如:
float*pointer_x;
int*pointer_i;
作用:
定义某些变量为指针类型,使之专门用于存放地址。
注意:
(1)*用于定义指针变量,但指针变量名不带*
如int*point_i;
定义的指针变量为point_i,不是*point_i
(2)一个指针变量只能指向同一类型的变量
如int*point_i;
point_i只能用于指向整型变量。
9.2.2指针变量的引用
(1)取地址运算符&
(2)指针运算符*(取内容)
如:
若有变量定义:
inta,*pa;
a为变量;&a就是a的地址;
pa为指针变量;*pa就是pa指向的变量;
若pa=&a,则*pa实际就是a。
例如
main()
{inta,b;
int*pa,*pb;
a=100;b=10;
pa=&a;
pb=&b;
printf(“%d,%d\n”,a,b);
printf(“%d,%d\n”,*pa,*pb);
}
对*及&的说明:
(同级运算,由右向左)
例:
将两个整型数a,b按由大到小次序输出。
main()
{int*p1,*p2,*p,a,b;
scanf(“%d,%d”,&a,&b);
p1=&a;p2=&b;
if(a
{p=p1;p1=p2;p2=p;}
printf(“a=%d,b=%d\n”,a,b);
printf(“larger=%d,little=%d\n”,*p1,*p2);
}
运行情况:
5,9
a=5,b=9
larger=9,little=5
注意:
a和b并未交换,但p1和p2的值交换了
9.2.3指针变量作函数参数
作用:
将一个变量的地址传至另外一个函数中。
swap(p1,p2)
int*p1,*p2;
{intp;
p=*p1;
*p1=*p2;
*p2=p;
}
交换指针所指向的变量值
main()
{inta,b;
int*pa,*pb;
scanf(“%d,%d”,&a,&b);
pa=&a;pb=&b;
if(a
printf(“%d,%d\n”,a,b);
}
运行情况:
5,9
9,5
函数调用过程如下图所示:
开始调用swap函数,实参pa、pb分别向形式参数p1、p2传递数据
执行函数语句,p1、p2所指向的变量的值相互交换
函数调用结束后,p1、p2所占用的内存单元被释放,
·单向传递,值传递问题
swap(x,y)
intx,y;
{intt;
t=x;
x=y;
y=t;
}
main()
{inta,b;
scanf(“%d,%d”,&a,&b);
if(a
printf(“%d,%d\n”,a,b);
}
形参值的改变无法传递给实参
改变指针形参的值,也不能使指针实参的值改变
swap(p1,p2)
int*p1,*p2;
{int*p;
p=p1;
p1=p2;
p2=p;
}
C语言中,实参和形参间的数据是单向值传递方式。
指针做函数参数也遵循该原则
main()
{inta,b;
int*pa,*pb;
scanf(“%d,%d”,&a,&b);
pa=&a;pb=&b;
if(a
printf(“%d,%d\n”,*pa,*pb);
}
如输入数据为:
5,9
结果为:
5,9
9.3数组的指针和指向数组的
指针变量
·数组的指针:
数组的起始地址。
·数组元素的指针:
数组元素的地址。
·数组名可视为地址常量。
9.3.1指向数组元素的指针变量的定义与赋值
例如:
inta[10];
int*pa;
pa=a;(或pa=&a[0])
表明指针pa指向数组a的首地址;此时,指针对象*pa为a[0];
pa+n表示数组第n个数据的地址
即pa+n=&a[n]
*(pa+n)是a[n]
9.3.2通过指针引用数组元素
引用数组中的元素可以用以下方法:
下标法如a[3]
指针法即通过指向数组元素的指针找到所需的元素.这种方法占内存少,运行速度快,因此说程序的质量高.
假设p已定义为指针变量,并已赋了一个地址,它指向某一个
数组元素.且有赋值语句p=&a[0];则:
•p+1表示数组中的下一个元素,
•a+i和p+i都是a[i]的地址,或者说它们指向a[i].
•*(a+i)或*(p+i)是a+i或p+i所指向的数组元素。
•指向数组的指针变量也可带有下标,如p[i]与*(p+i)等价。
例:
输出数组全部元素
•下标法:
main()
{inta[10],i;
for(i=0;i<10;i++)
scanf(“%d”,&a[i]);
printf(“\n”);
for(i=0;i<10;i++)
printf(“%5d”,a[i]);
}
•通过数组名计算数组元素地址,找出数组元素
for(i=0;i<10;i++)
printf(“%5d”,*(a+i));
•用指针变量指向数组元素
for(p=a;p<(a+10);p++)
printf(“%5d”,*p);
例:
用指针处理数据。
#include“stdio.h”
main()
{inta[10],*pa,i;
for(i=0;i<10;i++)
a[i]=i+1;
pa=a;
for(i=0;i<10;i++,pa++)
printf(“%d”,*pa);
printf(“\n”);}
例:
给定10个整数,求最大值。
#include“stdio.h”
#defineN10
main()
{inta[N]={5,7,3,6,2,1,8,9,4,0};
inti,*p,max;
p=a;
max=*p++;
for(i=1;iif(*p>max)max=*p;
printf(“max=%d\n“,max);
}
9.3.3数组名作为函数参数
当用数组名作为参数时,如果形参数组中个元素的值发生
变化,实参数组元素的值也随之变化,为什么?
若有一个实参数组,想在函数中改变此数组的元素的值,实参与形参的对应关系有以下4种情况:
•形参与实参都用数组名
•实参用数组名,形参用指针变量
•实参形参均用指针变量
•实参为指针变量,形参为数组名
例如:
用选择法对10个整数排序
main()
{int*p,i,a[10];
voidsort();
p=a;
for(i=0;i<10;i++)
scanf(“%d”,p++);
p=a;
sort(p,10);
for(p=a,i=0;i<10;i++)
printf(“%d”,*p++);
}
voidsort(x,n)
intx[],n;
{inti,j,t;
for(i=0;i{for(j=i+1;jif(x[i]>x[j])
{t=x[i];
x[i]=x[j];
x[j]=t;}
}
}
9.3.4指向多维数组的指针和指针变量
一、多维数组的地址
假设数组名为a,起始地址设为200
Statica[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};则:
•a代表整个二维数组的首地址,即第0行的首地址
•a+1是数组a第1行首地址(208)
•a[0],a[1],a[2]是二维数组中三个一维数组的名字(地址),是第0行,第1行,第2行的首地址,即:
a[0]=a+0、a[1]=a+1、a[2]=a+2
•a[i]+j是第i行j列的地址
•*(a[i]+j)是该地址存储的值,
即a[i][j]
考虑*(a[2]+3)=?
注意:
•a[i]和*(a+i)无条件等价
•a+i、a[i]、*(a+i)、&a[i][0]均表示第i行首地址;
•&a[i][j]、a[i]+j、*(a+i)+j都是第i行j列元素的地址;
•a[i][j]、*(a[i]+j)、*(*(a+i)+j)都是第i行j列元素的值;
二、指向数组的指针变量
定义格式:
类型说明符(*变量名)[常量表达式]
功能:
定义一个名为“变量名”的指针变量,这个指针变量所指的对象是一个有“常量表达式”个元素的一维数组
例如:
若有int(*pa)[4];
则:
被定义成一个指针变量,它所指对象是一个有4个整型元素的数组
例如:
输出二维数组任一行任一列元素的值
main()
{inta[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(“a[%d][%d]=%d\n”,i,j,*(*(p+i)+j));
}
例如:
有一个班,3个学生,各学4门课,计算总平均分,以及第n个学生的成绩
voidaverage(p,n)
float*p;intn;
{floatsum=0,aver;
for(;p
sum=sum+(*p);
aver=sum/n;
printf(“average=%6.2f\n”,aver);
}
voidsearch(p,n)
float(*p)[4];intn;
{inti;
printf(“thescoreofNo.%dare:
\n”,n);
for(i=0;i<4;i++)
printf(“%6.2f“,*(*(p+n)+i));}
main()
{floatscore[3][4]={{65,67,70,80},{80,90,78,91},
{70,79,75,89}};
average(score,12);
search(score,2);
}
9.4字符串的指针和指向字符串的指针变量
9.4.1字符串的表示形式
1用字符数组表示,如:
mian()
{staticcharstring[]=“IloveChina!
”;
printf(“%s\n”,string);
}
2用字符指针实现,如:
mian()
{char*string=“IloveChina!
”;
printf(“%s\n”,string);
}
运行结果:
IloveChina!
请编写函数intfun(char*str),它的功能是判别字符串str是否是"回文",若是,返回1,否则返回0.
例如,“13531”,“helleh”是回文,但“1353”,“Helleh”不是回文.
#include"stdio.h"
intflag=0;
intfun(char*str)
{intn=0,k;
char*p1=str;
flag=0;
while(*p1){n++;p1++;}
for(k=0;kif(*(str+k)==*(str+n-k)flag=1;
returnflag;}
voidmain()
{chars[128];
printf("\nPleadeenterstring:
\n");
gets(s);
fun(s);
}
字符指针使用中的几点事项:
1.要注意一些常用的符号。
如串的结束符是‘\0’
它的数值为0;回车符的数值为13;换行符
的值为10;文件结束符的数值为27;
2.字符指针常用于文件操作。
3.前面讲过的指针使用中要注意的问题同样适用于字符指针。
字符指针变量与字符数组的比较:
·字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是字符串的首地址。
·赋值方式:
对数组的赋值方法有:
charstr[]=“Iamaboy!
”
或:
charstr[20];
scanf(“%s”,str);
对字符指针变量的赋值方法有三种:
(1)char*pa=“Iamaboy!
”
(2)
(2)char*pa;
pa=“Iamaboy!
”
(3)char*pa,str[20];
pa=str;
scanf(“%s”,pa);
9.5函数的指针和指向函数的指针变量
9.5.1用函数指针变量调用函数
可以用指针变量指向一个函数。
一个函数在编译时被分配一个入口地址,这个入口地址称为函数的指针。
例:
求a和b中的大者。
main()
{intmax();
int(*p)();
inta,b,c;
p=max;
scanf(%d,%d”,&a,&b);
c=(*p)(a,b);
printf(“a=%d,b=%d,max=%d”,a,b,c);
}
说明:
1.指向函数的指针变量的一般定义形式是:
数据类型标识符(*指针变量名)();
2.函数的调用可以通过函数名调用,也可以通过函数指针调用;
3.在一个程序中,一个指针变量可以先后指向不同的函数;
例如:
int(*p)();
intmax();
intmin();
p=max;c=(*p)(a,b);
······
p=min;c=(*p)(a,b);
4.在给函数指针变量赋值时,只需给出函数名而不必给出参数;
5.用函数指针变量调用函数时,只需将(*p)代替函数名即可(p为指针变量名),(*p)后的括号中应加相应实参。
9.5.2把指向函数的指针变量作函数参数
指向函数的指针变量可以也作为参数,以便实现函数地址的传递,即将函数名传给形参。
9.6返回指针值的函数
即可带回指针值的函数,其一般定义形式为:
类型标识符*函数名(参数表);
如int*a(x,y);
例如:
有若干学生的成绩(每人四门),要求输入序号后,能输出该生全部成绩。
main()
{floatscore[][4]={{60,70,80,90},{57,89,46,78},{43,90,87,67}};
float*search();
float*p;
inti,m;
printf(“enterthenumberofstudent:
”);
scanf(“%d”,&m);
printf(“ThescoresofNo.%dare:
\n”,m);
p=search(score,m);
for(i=0;i<4;i++)printf(“%5.2f\t”,*(p+i));
}
float*search(pointer,n)
float(*pointer)[4];
intn;
{float*pt;
pt=*(pointer+n);
return(pt);
}
运行情况:
enterthenumberofstudent:
1
ThescoresofNo.1are:
57.00,89.00,46.00,78.00
9.7指针数组和指向指针的指针
9.7.1指针数组
指针数组:
由相同类型的指针变量排列而成的有序集合(每个元素都是指针变量)。
说明格式:
类型说明符*指针数组名[元素个数]
如int*p[5]注意与int(*p)[5]不同
一般用于指向若干个字符串,使字符处理更方便。
例如:
#include“stdio.h”
main()
{char*s[4]={“dog”,“cat”,“pig”,“allanimal”};
inti;
for(i=0;i<4;i++)
printf(“%s\n”,*(s+i));
}
9.7.2指向指针的指针(二级指针)
·指向指针的指针:
指向指针数据的指针变量。
通常用于指向字符型指针变量。
·说明格式:
类型说明符**指针变量名
例如:
char**p;
其含义是定义指针变量p,用于存储另一个指针变量的地址。
例如:
mian()
{char*s[]={“China”,“Japan”,“English”,”Franch”};
char**p;
inti;
p=s+2;/*p=*(s+2)=s[2]存放的是English的首地址*/
printf(“%s\n”,p);/*打印p指针内的内容,即指针指向的字符串*/
}
9.7.3main()函数的命令行参数
通常,main函数首行为main(),其实可带参数,如:
main(argc,argv)
intargc;
char*argv[];
{………
}
main函数的实参是和命令一同给出的,即在一个命令行中包括命令名和需要传给main函数的参数
命令行的一般形式为:
命令名参数1参数2…...参数n
假设目标文件名为“F”,需向函数传递的参数为字符串“X”和“Y”,则命令行可写为:
FXY
命令行及命令行参数提供了C程序与操作系统间的接口
若有一个函数,其所在文件名为“F”:
main(argc,argv)
intargc;
char*argv[];
{while(argc>1)
{++argv;
printf(“%s\n”,*argv);
--argc;}
}
若输入的命令行参数为
FABCDEF
则执行结果为
ABC
DEF
9.8有关指针的数据类型和指针运算小节
(一)有关指针的数据类型
·inti;……….定义整型变量i;
·int*p;……..p为指向整型数据的指针变量;
·inta[n];……定义整型数组a,它有n个元素;
·int*p[n];…..定义指针数组p,它由n个指向整型数据指针元素组成;
·int(*p)[n];…定义指向含n个元素的一维数组的指针变量p;
·intf();……..f为带回整型函数值的函数;
·int*p();…p为带回一个指针的函数,该指针指向整型数据;
·int(*p)();….p为指向函数的指针,该函数返回一个整型值;
·int**p;…….p是一个指针变量,它指向一个指向整型数据的指针变量。
(二)指针运算小结
1.赋值=
语法:
指针变量=指针表达式
若有变量定义:
int*p1,*p2,a,array[10];
·p1=&a;………….变量的地址。
’
·p2=array;…………数组的首地址。
·p2=&array[i];…….数组第i个元素的地址。
·p1=p2;…………..一个指针变量值赋给另一个指针变量。
2.取地址运算&
语法:
&变量
设有变量说明inta,b,*p,*q;
p=&a;把a的地址赋给p,即让p指向a
q=p;让q也指向a,现在p、q都指向a
p=&b;让p也指向b,现在q指向a,p指向b
其中&a表示a的地址值
3.取内容运算*
语法:
*指针表达式
设p是一个指针表达式,则:
(1)若*p出现在赋值号左边,表示给p所指变量赋值
(2)若*p不出现在赋值号左边,表示p所指变量的值
若有变量说明:
inta,*p;则:
p=&a;让p指向变量a
*p=10;*p出现在赋值号左边,等价于a=10
printf(“%d”,*p);*p不出现在赋值号左边,打印p所指变量的值
scanf(“%d”,&a);给变量a输入值
scanf(“%d”,p);同上
*p+25等价于a+25
4.指针表达式与整数相加减
形式:
p+n或p-n
其中:
p是任意一个指针表达式,n是任何一种整型表达式
计算规则:
表达式p+n的值=p的值+p所指类型长度*n
表达式p-n的值=p的值-p所指类型长度*n
说明:
只有当p和p+n或p-n都指向连续存放的同类型数据区域,例如数组时,指针加减才有实际意义。
C语言规定:
表达式p+n和p-n的类型与p相同。
例如:
设有变量定义:
inta[10],*p,*q;则
p=ap指向a[0]
q=a+6q指向a[6]
p=q-4p指向a[2]
5.自增自减运算
语法:
p++;p--;++p;--p;
例如:
设有变量定义:
inta[]={1,2,3,4,5},*p,*q;
p=q=&a[3];
*p++=100;a[?
]变成100
*++q=100;a[?
]变成100
p++与++p的区别:
表达式p++的值等于p的原来值;
表达式++p的值等于p的新值;
6.关系运算
只有同类指针进行比较才有意义
·==和!
=运算符,比较的是两个指针表达式是否指向同一个内存单元;
·<、<=、>、>=,比较的是两个指针所指内存区域的先后次序
·语法:
指针表达式关系运算符指针表达式
若有变量定义:
inta[10];int*p=a,*q=a+3;
试判断以下表达式的值
p==&a[0]p==&a[1]p==qp+4=q+2pq>a+2p>q
可用以下语句给数