第十章 指针第一节 指针的基本概念
1.指针 —— 变量的地址当 C源程序在编译时,编译程序对遇到的变量分配连续的内存单元,
5011
5003
5004
5005
5006
5007
5008
5009
5010
5002
5001
5012
例,有变量定义语句如下,
short a=3;long b=5;float c;
编译系统给变量分配的存储空间如下,
3
5
short型变量 a
long型变量 b
float型变量 c
注意,
C语言规定,如果一个变量占用一个字节时,该字节的地址就是该变量的地址 ;如果变量用连续的多个字节,那么第一个字节的地址就是该变量的地址,
变量、数据类型和地址对照表变量名 数据类型 地址
a
b
c
short
long
float
5001
5003
5007
5011
5003
5004
5005
5006
5007
5008
5009
5010
5002
5001
5012
3
5
a
b
c
若运行时执行语句:
c=a+b;
+ 8
8
2.指针变量 —— 用于存放地址的变量直接访问:通过变量名直接使用变量间接访问:将变量的 地址 存放到另一个,特殊,的变量 中,通过该变量来存取变量的值地址 —— 指针
,特殊,的变量 —— 指针变量
C程序中,变量的值是通过运算符,&”
来得到,它的运算对象是变量或数组元素,
得到的结果是数组元素的地址如,int a,b[10];
&a; /*得到变量 a的地址 */
&b[5]; /*得到数组元素 b[5]的地址 */
第二节 指针变量的定义、引用及运算
1.指针变量的定义与初始化数据类型 *指针变量名说明,
( 1)与其他变量定义一样,可以一次定义多个指针变量并赋初值
( 2),数据类型,指该指针变量用于存放何种数据类型的地址说明,
( 3)定义指针变量时,指针变量名前必须有一个
,*”,作为定义一指针变量的标志
( 4)初值形式:
如,float a,f1[10];
float *p1=&a; /*定义一个指针变量 p1,
p1指向 a*/
float *p2=&f1[8]; /*定义一个指针变量 p2,
p2指向 f1[8]*/
float *p3=f1; /*定义一个指针变量 p3,
p3指数组向 f1第一个元素 */
2.指针变量的引用方式
1)给 指针变量赋值指针变量名 =地址表达式如,int a,*p;
p=&a; /*定义一个指针变量 p,指向变量 a*/
2)直接使用 指针变量如,int a,b,c,*p1=&a,*p2=&b;
scanf(“%d,%d,%d”,p1,p2,&c);
3)通过 指针变量来引用变量
*指针变量如,int a=4,b=6,c,*p1=&b,*p2=&c;
*p2=a+*p1*b;
printf(“%d”,c);
/*c=a+b*b*/
1) &运算符
3.有关运算符如,&x;
&a[5];
2) *运算符如,int a,*p=&a;则
&a 代表 *p 代表
&*a 代表 *&p 代表
*&a 代表 &*p 代表例,指针变量算术运算
main()
{ short a=1,b=2,c=3,*p1=&b;
float d=4.0,e=5.0,f=6.0,*p2=&e;
printf(“%x,%d\n”,p1,b);
p1++;
printf(“%x,%d\n”,p1,c);
p1=p1-2;
printf(“%x,%d\n”,p1,a);
printf(“%x,%f\n”,p2,d);
p2++;
printf(“%x,%f\n”,p2,e);
p2=p2-2;
printf(“%x,%f\n”,p2,f);
}
main()
{ short a=1,b=2,*p1=&a,*p2=&b;
printf(“p1>p2=%d\n”,p1>p2);
printf(“p1<=p2=%d\n”,p1<=p2);
printf(“p1&&p2=%d\n”,p1&&p2);
}
例,指针变量逻辑运算假设 a的地址为,ffd4,
b的地址为,ffd6
0
1
1
第三节 指针与变量如,int a,*pa;
pa=&a; 假设要给 a赋值 3?
a
3
直接赋值
a=3;
pa
&a
a
3
间接赋值
*pa=3;
main()
{ int a=3,b=5,t,*p1=&a,*p2=&b;
printf(“%d\t%d\n”,a,b);
t=*p1;
*p1=*p2;
*p2=t;
printf(“%d\t%d\n”,a,b);
}
例 1,改变 指针变量指向的变量值
main()
{ int a=3,b=5,*t,*p1=&a,*p2=&b;
printf(“a:value%d\tb:value%d\n”,a,b);
t=p1;
p1=p2;
p2=t;
printf(“a:value%d\tb:value%d\n”,a,b);
}
例 2,只交换 指针变量的值,将不影响指针变量指向值
*p1,*p2);
第四节 指针与一维数组
1.指向一维数组 元素 的 指针变量如,int a[5],*p=a;
int a[5],*p;p=a;
int a[5],*p=&a[0];
int a[5],*p;p=&a[0];
a[0]
a[1]
a[2]
a[3]
a[4]
a p
a+1,p+1?
a+1 p+1
i,i?
a+3 p+3
a+i,p+i代表 &a[i]
说明,
2)当指针变量 p指向了数组的首元素之后,
数组 a[i]可以表示为下以下几种形式:
a[i]
数组 a[i]的地址可以表示为下以下几种形式
&a[i]
1)在 C语言中,有一个等式永远成立,即 a[i]无条件等价于 *(a+i)
*(p+i) *(a+i) p[i]
p+i a+i &p[i]
main()
{
int a[10]={1,2,3,4,5,6,7,8,9,10},k,*p=a;
k=*(p+2)+p[3]+a[3]+a[4]+*(a+7);
printf(“%d\n”,k);
}
例 1,写出下列程序的运算结果
24
main()
{
int a[10]={1,2,3,4,5,6,7,8,9,10},k,*p;
p=&a[4];
k=*(p+2)+p[3]+a[3]+a[4]+*(a+7);
printf(“%d\n”,k);
}
例 2,写出下列程序的运算结果
32
2,指向一维数组的 指针变量的运算
1)指针变量的算术运算指向数组的指针变量 (p)只能和整数 (N)
进行简单的算术运算和关系运算
p+N p-N
++p --p
p++ p--
a+N a-N
++a --a
a++ a--
main()
{
int a[10]={1,2,3,4,5,6,7,8,9,10},k,*p;
p=a;
k=*(p+4)+*p++;
printf(“%d\n”,k);
}
例,写出下列程序的运算结果
6
2)指针变量与指针变量的减法运算如果两个指针变量指向同一个数组,它们可以进行减法运算。运算法则:
指针变量 1-指针变量 2
注意,
进行减法运算的两个指针变量必须指向同一数组,
它们的差并不是它们地址值的差,而是它们所指向的数组元素下标之差
main()
{
int a[10]={1,2,3,4,5,6,7,8,9,10},*p1,*p2;
p1=&a[3];
p2=&a[8];
printf(“%d,%d\n”,p1-p2,p2-p1);
}
例,指针变量与指针变量之差
-5,5
3)指针变量间的关系运算指向某一数组中元素的两个指针变量还可以进行关系运算。运算法则:
指针变量 1 关系运算符 指针变量 2
注意,
( 1)如果指针变量 1中的地址值和指针变量 2
中的地址值满足关系运算时,式子的值为
1(真),否则 0(假)
( 2)指针变量间的关系运算在处理数组的循环中常作为循环的控制条件
main()
{
int a[10],*p1,*p2;
p1=&a[3];
p2=&a[4];
printf(“%d,%d,%d,%d\n”,
p1<p2,p1-a,p1<&a[9],p2<&a[4]);
}
例 1,指针变量间的关系运算
1,3,1,0
main()
{
int a[10],i;
for(i=0;i<10;i++)
scanf(“%d”,&a[i]);
for(i=0;i<10;i++)
printf(“%d\n”,a[i]);
}
例 2,输出数组中所有元素
a[0]
a[1]
a[2]
… …
a[9]
a p
main()
{
int a[10],i;
for(i=0;i<10;i++)
scanf(“%d”,&a[i]);
for(i=0;i<10;i++)
printf(“%d\n”,*(a+i));
}
main()
{
int a[10],*p,i;
for(p=a;p<(a+10);p++)
scanf(“%d”,p);
for(p=a;p<(a+10);p++)
printf(“%d\n”,*p);
}
,*p=a,i;
for(i 0 i 10;i++)
,p++);
for(i 0 i 10;i++,p++
main()
{ int a[10],*p=a;
float sum;
for(;p<a+10;p++)
scanf(“%d”,p);
sum=0.0;
for(p=a;p<a+10;p++)
sum=sum+*p;
sum=sum/10.0;
printf(“\naver=%f”,sum);
}
例 3,从键盘输入 10个数,求出 10个数的平均值第五节 指针与字符串
1.指针变量指向字符串的方法方法 1 给指针变量赋初值
char *p=“student”;
方法 2 给指针变量赋值
char *p;
p=“student”;
ps
t
u
d
e
n
t
\0
char s[20];
s=“student”;
2.指向字符串常量或字符数组的指针变量的使用
1)把字符串当作整体来处理输出字符串,printf(“%s,指针变量);
puts(指针变量);
输入字符串,scanf(“%s,指针变量);
gets(指针变量);
2)处理字符串中单个字符
*(指针变量 +i)
例 1:写出下列程序的运算结果
#include <stdio.h>
main()
{ char a[]="Language",b[]="Programe";
char *p1,*p2;
int k;
p1=a;
p2=b;
for(k=0;k<=7;k++)
if(*(p1+k)==*(p2+k))
printf("%c",*(p1+k));
}
gae
例 2,从键盘输入一个字符串,存入数组中,求出输入的字符串长度分析,strlen( )函数,若不用该函数先考虑字符串的存放形式 pa
s
p


\0
第六节 指针与二维数组
1.指针变量指向二维数组的某个元素赋初值,
数据类型符 *指针变量名 =&数组名 [下标 1][下标 2]
char *p=&a[3][4];
赋值方式:
指针变量 =&数组名 [下标 1][下标 2]
char *p;
p=&a[3][4];
例,写出下列程序的运算结果
main()
{
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12},
*p=&a[1][2],k;
k=*p+*(p+2);
printf(“%d”,k);
}
1 2 3 4
5 6 7 8
9 10 11 12
16
1)
2.指针变量指向二维数组的首元素
)让指针变量指向二维数组首地址的方法格式 1:
数据类型符 *指针变量名 =&数组名 [0][0]
char *p=&a[0][0];
格式 2:
数据类型符 *指针变量名 =数组名
char *p=a;
2)二维数组元素的引用方法如,int a[3][4],*p=&a[0][0];
a[0][0] a[0][1] a[0][2] a[0][3]
a[1][0]
a[2][0]
a[1][1] a[1][2] a[1][3]
a[2][1] a[2][2] a[2][3]
p p+1
p+11
a[i][j]的地址可以表示为?
例,
main()
{ 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);
}
} 1 3 5 7
9 11 13 15
17 19 21 23
例,从指针法求二维数组的最大值及其下标
#define M 3
#define N 4
main()
{ int a[M][N],max_i,max_j,i,j;
int *p=&a[0][0];
for(i=0;i<M;i++)
for(j=0;j<N;j++)
scanf(“%d”,p++);
… …
}
3.用指向数组的指针变量指向数组的某一行
a[0]
a[1]
a[2]
a
a+1
a+2
a[0][0]
a[1][0]
a[2][0]
a[0][1]
a[1][1]
a[2][1]
a[0][2]
a[1][2]
a[2][2]
a[0][3]
a[1][3]
a[2][3]
a[0]+0
a[1]+0
a[2]+0
a[0]+1
a[1]+1
a[2]+1
a[0]+2
a[1]+2
a[2]+2
a[0]+3
a[1]+3
a[2]+3
二维数组模型用数组名表示各元素地址
1)指向一维数组的指针变量的定义数据类型 ( *指针变量) [长度 ]
注意,
定义时,,(),不能丢,从优先级考虑
2)用指向一维数组的指针指向二维数组的首行如,int a[3][4],(*p)[4]=a;
int a[3][4],(*p)[4];
p=a;
a[0]
a[1]
a[2]
p
p+1
p+2
a[0][0]
a[1][0]
a[2][0]
a[0][1]
a[1][1]
a[2][1]
a[0][2]
a[1][2]
a[2][2]
a[0][3]
a[1][3]
a[2][3]
二维数组模型
*(p+0)+0
*(p+1)+0
*(p+2)+0
*(p+0)+1
*(p+1)+1
*(p+2)+1
*(p+0)+2
*(p+1)+2
*(p+2)+2
*(p+0)+3
*(p+1)+3
*(p+2)+3
用指针变量表示各元素地址
*( *(p+0)+0)
*( *(p+1)+0)
*( *(p+2)+0)
*( *(p+0)+1)
*( *(p+1)+1)
*( *(p+2)+1)
*( *(p+0)+2)
*( *(p+1)+2)
*( *(p+2)+2)
*( *(p+0)+3)
*( *(p+1)+3)
*( *(p+2)+3)
用 指针变量 表示各元素地址
a[i][j]的地址可以表示为? a[i][j]可表示为?
main()
{
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int (*p)[4]=a,i,j;
for(i=0;i<3;i++)
{ for(j=0;j<4;j++)
printf(“a[%d]+%d=%x”,i,j,a[i]+j);
printf(“\n”);
}
}
例 1:
main()
{
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int (*p)[4]=a,i,j;
for(i=0;i<3;i++)
{ for(j=0;j<4;j++)
printf(“*(a[%d]+%d)=%d”,i,j,*(a[i]+j));
printf(“\n”);
}
}
例 2:
main()
{
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int (*p)[4]=a,i,j;
for(i=0;i<3;i++)
{ for(j=0;j<4;j++)
printf(“*(p+%d)+%d)=%x”,i,j,*(p+i)+j));
printf(“\n”);
}
}
例 3:
main()
{
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int (*p)[4]=a,i,j;
for(i=0;i<3;i++)
{ for(j=0;j<4;j++)
printf(“*(*p+%d)+%d)=%d”,i,j,*(*(p+i)+j));
printf(“\n”);
}
}
例 4:
例 5:输出一二维数组中任一元素值例 6:输入一个 3× 4的二维整型数组,求出每行的最大值、最小值及其下标第七节 指针与函数
1,指针作为函数的参数例 1,写出下列程序的执行结果
main()
{ int a=25;
print_a(&a);}
print_a(int *x)
{ printf(“%d\n”,++*x); } 26
例 2,写出下列程序的执行结果
int c=6;
void test(int *x,y)
{ *x=3*(*x);
y=*x+y;
c=y%(*x);
printf(“x=%d,y=%d,c=%d\n”,*x,y,c);}
main()
{ int a=1,b=4;
test(&a,b);
printf(“a=%d,b=%d,c=%d\n”,a,b,c);}
3,7,1
3,4,1
例 2,编一个函数将两个变量的值交换,在主函数中调用该函数加以验证
main()
{
int a,b,*pa=&a,*pb=&b;
scanf(“%d,%d”,pa,pb);
change(pa,pb);
printf(“%d,%d\n”,a,b);
}
change(int *p,int *q)
{
int t;
t=*p;
*p=*q;
*q=t;
}
2,数组名作为函数的参数数组名作为函数的参数,在函数间传递的不是整个数组,而是数组的首地址,也就是说,
形参数组与实参数组指的是同一个数组因此,在被调函数中改变了形参数组中某个元素的值,其对应的实参数组元素也跟着发生改变例 1:写出下列程序的运算结果
#include,stdio.h”
#include,string.h”
fun(char *s)
{ char a[7];
s=a;
strcpy(a,”look”); }
main()
{ char *p;
fun(p);
puts(p); } look
例 2,编一个函数,把一个数组中的最大元素和最后一个元素值互换,最小元素和第一个元素值互换。数组名、元素个数作为函数的参数,调用时与数组名对应的实参为指针变量第八节 指针数组数据类型 *指针数组名 [长度 ]={初始值 }
如,int *p[4]
注意,
与指向指针数组的指针变量的定义区别,
不能写成 (*p)[4]
main()
{
int a=4,b=5,c=6;
int *p[3],k;
p[0]=&a;
p[1]=&b;
p[2]=&c;
k=*p[0]+*p[1]+ *p[2];
printf(“%d”,k);
}
例 1,写出下列程序的执行结果
15
#include <stdio.h>
main()
{ char *p[]={“BOOK”,”OPK”,”H”,”SP”};
int i;
for(i=3;i>=0;i--)
printf(“%c”,*p[i]);
prinf(“\n”);
}
例 2,写出下列程序的执行结果例 3:从键盘输入 10个字符串并存入一个二维字符数组中,然后定义一个指针数组,使其各元素分别存放这 10个字符串的首地址,并输出这 10
个字符串