第十章 指针任课老师:台安返回下一页上一页第十章 指针
10.1 指针的概念
10.2 变量的指针和指向变量的指针变量
10.3 数组的指针和指向数组的指针变量
10.4 字符串的指针和指向字符串的指针变量
10.5 函数的指针和指向函数的指针
10.6 返回指针值的函数
10.7 指针数组和指向指针的指针
10.8 指针数据小结返回下一页上一页
变量的两个概念,
对应的地址 (内存单元)
对应的值 (具体的数值)
变量的地址 =变量的指针,指向变量在内存中的存储地址。
两种访问变量 a的方式:
1 直接访问,通过变量 a找到棋对应的存储地址。
2 间接访问,把变量 a的地址放到另一个变量 b中,通过变量 b来访问变量 a。变量 b就称为指针变量。
指针变量:存放变量的地址的变量
指针类型,指针所指对象的数据类型,
§ 10.1 指针的概念返回下一页上一页例如:
int i,j,k,*ip,*jp,*kp;
i=3; j=6; k=i+j;
ip=&i;
jp=&j;
kp=&k;
*kp=*ip+*jp;
3
6
9
….
2000
2002
2004
2000
2002
2004
3010
3012
3014
i
j
k
ip
jp
kp
定义指针变量给指针变量赋值给指针变量所指对象赋值返回下一页上一页
§ 10.2 变量的指针和指向变量的指针变量
变量的指针:就是变量的地址。
如 i 所对应的内存地址是 2000,则 i 的指针就是 2000;
指针变量:用来存放变量地址的变量。
int i=3;
int *ip;
ip = &i
2000 3
ip
i2000
*ip
3100
ip所对应的地址是 3010,对应的内容是 2000,2000就是 i 所对应的地址,因此,ip是存放变量 i 的地址的变量。 若 ip 是存放变量 i 的地址的指针变量,则 *ip是指针变量 ip所指的对象(即变量 i ),
返回下一页上一页
10.2.1指针变量的定义
指针变量在使用前必须先定义,且赋值,
以便使其指向特定类型的变量。
指针变量的定义形式,
类型标识符 * 标识符
其中,类型标识符,指出指向何种数据类型的变量
标识符,表示指针变量名,
返回下一页上一页例如:
int i,j;
int *p1,*p2;
p1=&i; p2=&j;
i=3; j=5;
*p1=8; *p2=12;
float * p3;
char * p4;
说明,
1.定义 时指针变量名前必须以‘ *’开头,指出该变量是指针变量。
2.引用 时,指针变量前加
‘ * ’ 表示指针变量所指向的对象(即变量 )
(注意两者的区别)。
3.指针变量一经定义就只可指向同类型的变量。
如,p3只能指向实型变量。
返回下一页上一页
10.2.2 指针变量的引用
通常,是将变量的地址赋给指针变量,但在 Turbo
c中,整型数据(十进制、十六进制、八进制)
也可赋给指针变量,
如,int *p1;
p1=100;
printf(“%d\ n”,* p1);
指针变量有两种运算符:
&:取地址运算符,
如,p1=&i;
*,取所指变量运算符。或者访问目标的运算符
如,* p1,它与 i 等价返回下一页上一页
10.2.2 指针变量的引用
编译时,系统将内存单元分配给变量后,程序执行时对变量的操作实际上就是根据变量名查找与之对应的变量的地址,然后对地址中的数据进行操作。
1.直接访问
k = i + j
2.间接访问 * kp = * ip + *jp
这里,i p,j p,k p:就称为指针变量,其值是另一个变量所对应的内存地址。
返回下一页上一页例,指针变量操作简例
main( )
{ int a,b,*p1,*p2 ;
a=100; b=10;
p1=&a; p2=&b;
printf(“a=%d,b=%d\ n”,a,b);
printf(“* p1=%d,* p2=%d\ n”,*p1,* p2);
printf(“&a=%x,& b=%x\ n”,&a,&b);
printf(“p1=%x,p2=%x\ n”,p1,p2);
printf(“& p1=%x,&p2=%x\ n”,&p1,& p2);
}
a=100,b=10
*p1=100,*p2=10
&a=fff4,&b=fff2
p1=fff4,p2=fff2
&p1=fff0,&p2=ffee
返回下一页上一页关于 & 和 * 运算符的进一步说明:
*,&:优先级同为 2级,
结合性:从右向左。
1.若已定义且执行:
int a,b,* p1,* p2;
p1=&a; p2=&b; a=100; b=10;

① &* p1? &a? p1;
&* p2?&b? p2
② 若 p2=&* p1? p2=&a
返回下一页上一页关于 & 和 * 运算符的进一步说明:
2,* & a,先进行 &a得 a的地址,再对 a的地址进行 * 运算,即指向 a地址所指向的变量,也就是 a,其值是 100
3.运算符 *,++,优先级为 2,结合性,从右到左
(* p1)++? a++
* p1++? * (p1++)
意即,将 p1所指向的对象 a 的值取出,然后使 p1
自增,p1原指向 a,现在可能指向下一个变量了,
返回下一页上一页
main( )
{int a,*p;
a=5; p=&a;
printf(“a=%d,p=%x\n”,a,p);
printf(“a=%d\n”,*p++);
printf(“a=%d,p=%x\n”,a,p);
}
例:
输出结果:
a=5,p=fff4
a=5
a=5,p=fff6
返回下一页上一页例:指针交换指向
main( )
{int a=3,b=4,t ;
int *p1,*p2;
p1=&a; p2=&b;
printf(“%d,%d\n”,a,b);
t=*p1; *p1=*p2; *p2=t;
printf(“%d,%d\n”,a,b);
}
3 4a b
p1 p2
4 3a b
返回下一页上一页稍作改动:改变中间变量,有何不同?
main( )
{int a=3,b=4;
int *p1,*p2,*t;
p1=&a; p2=&b;
printf(“%d,%d\n”,a,b);
t=p1; p1=p2; p2=t;
printf(“%d,%d\n”,a,b);
}
3 4a b
p1 p2
3 4a b
返回下一页上一页
main( )
{int a=3,b=4;
int *p1,*p2,*t;
p1=&a; p2=&b;
printf(“%d,%d\n”,a,b);
*t=*p1; *p1=*p2; *p2=*t;
printf(“%d,%d\n”,a,b);
}
错例:
中间指针变量的使用:
给未知地址空间赋值。
请问同学们:
错在何处?
返回下一页上一页
10.2.3 指针变量作为函数参数
指针变量作为函数参数时,传递的是变量的地址。
main( )
{int a=3,b=4 ;
int p1=&a,p2=&b;
printf(“%d,%d\n”,*p1,*p2);
swap(p1,p2);
printf(“%d,%d\n”,*p1,*p2);
}
swap(int *p,int *q)
{int temp;
temp=*p;
*p=*q;
*q=temp;
}
输出,3,4
4,3
返回下一页上一页稍作改动:有何不同?
main( )
{int a=3,b=4 ;
int p1=&a,p2=&b;
printf(“%d,%d\n”,*p1,*p2);
swap(p1,p2);
printf(“%d,%d\n”,*p1,*p2);
}
swap(int *p,*q)
{int *t;
t = p;
p = q;
q = t;
}
输出,3 4
3 4
返回下一页上一页结论:
形参与实参之间的数据传递(指针或普通变量)是单向的值传递,实参中指针的值并没有改变,变量 a,b的值也没改变。
返回下一页上一页例,输入 a,b,c三个整数,按从大到小顺序输出
swap(int *pt1,int *pt2)
{
int p;
p=*pt1; *pt1=*pt2; *pt2=p;
}
exchange(int *q1,int *q2,int *q3)
{ if(*q1 < *q2) swap(q1,q2);
if(*q1 < *q3) swap(q1,q3);
if(*q2 < *q3) swap(q2,q3);
printf(“*q1=%d,*q2=%d,*q3=%d\n”,*q1,*q2,*q3);
}
返回下一页上一页例,输入 a,b,c三个整数,按从大到小顺序输出
main( )
{ int a,b,c,*p1,*p2,*p3;
scanf(“%d%d%d”,&a,&b,&c);
p1=&a; p2=&b; p3=&c;
printf(“&a=%x,&b=%x,&c=%x,a=%d,b=%d,c=%d\
n”,&a,&b,&c,a,b,c);
printf(“&p1=%x,&p2=%x,&p3=%x,p1=%x,p2=%x,
p3=%x\n”,&p1,&p2,&p3,p1,p2,p3);
printf(“*p1=%d,*p2=%d,*p3=%d,n”,*p1,*p2,*p3);
exchange(p1,p2,p3);
printf(“a=%d,b=%d,c=%d\ n”,a,b,c);
}
返回下一页上一页
§ 10.3 数组的指针和指向数组的指针变量在 C语言中,数组名代表了数组的起始地址。如果有数组 a,则 a的值就是该数组的起始地址,也是元素 a[0]的地址。下一个元素 a[1]的 地址可表示为 a+1,再下一个元素的地址为 a+2 ……,以此类推。
引用数组元素:
( 1)下标法,a[i]
(2) 指针法:用指针变量指向数组元素。
如,p=a ; p=p +i ;
( 3)地址法,*(a+i)
返回下一页上一页
10.3.1 指向数组元素的指针变量的定义和赋值
main( )
{ int a[5];
int *p=&a[0]; /* 指针变量 P指向了数组 a */
*p=2;
printf(“&p=%x,p=%x\ n”,&p,p);
printf(“&a=%x,&a[0]=%x,a[0]=%d\ n”,
&a,&a[0],a[0]);
printf(“*p=%d\n”,*p);
}
返回下一页上一页
10.3.2 通过指针引用数组元素
int a[10];
int *p;
p=a;
则 (1)
p+0 指向第 0个元素;
p+1 指向第 1个元素 ;
p+i 指向第 i个元素返回下一页上一页指针运算和地址运算
(2) p+i? a+i? &a[i] 意义相同,第 i个元素的地址。
(3) 指向数组的指针变量可带下标
如,p[i],a[i],* (a+i),* (p+i) 都是指向数组 a的第 i个元素。
返回下一页上一页举例:用五种方法输出数组元素 (1)
例 T10-5.c 用下标法
main( )
{ int i,a[5]={55,66,77,88,99};
for(i=0; i<5; i++)
printf(“%d\ n”,a[i] );
}
返回下一页上一页举例:用 五 种方法输出数组元素 (2)
例 T10-5-1.c 数组元素地址法
main( )
{ int i,a[5]={55,66,77,88,99};
for(i=0;i<5;i++)
printf(“%d\ n”,*(a+i));
}
返回下一页上一页举例:用 五 种方法输出数组元素 (3)
例 T10-5-2.c 用指针变量指向数组元素法
(指针法)
main( )
{ int *p,a[5]={66,66,77,88,99};
for(p=a; p< (a+5); p++)
printf(“p=%x,*p=%d\ n”,p,* p);
}
返回下一页上一页举例:用 五 种方法输出数组元素 (4)
例 T10-5-3.c 用指针变量地址法,输出数组元素
main( )
{ int i,* p,a[5]={55,66,77,88,99};
p=a;
for(i=0;i<5;i++)
printf(“%d\ n”,*(p+i));
}
返回下一页上一页举例:用 五 种方法输出数组元素 (5)
例 T10-5-3.c 用指针变量下标法,输出数组元素
main( )
{ int i,* p,a[5]={55,66,77,88,99};
p=a;
for(i=0;i<5;i++)
printf(“%d\ n”,p[i]);
}
返回下一页上一页使用指针变量时要注意的问题:
(1) p++,合法,因 p是指针变量,而且变量可以用 ++运算符的。
a++,不合法,因为 a是数组名,其值是数组元素的首地址,是常量。
(2) 指针变量使用时要注意当前值,
(3) 数组下标越界时,编译不作检查,要避免这种情况。
返回下一页上一页使用指针变量时要注意的问题:
(4) 指针变量使用时的几个问题,若 p=a 则:
① p ++,指针指向 a[1],
* p,是取出 a[1]的值
② *p++ 等价于 *(p++),优先级同为 2,从右向左结合,将 p所指数组元素的值取出,后再使 p增 1,指向下一个元素。
③ * (++p),先将 p增 1使其指向下一个元素,然后将该元素取出,
返回下一页上一页指针变量使用时的几个问题
④ (*p)++,将 p所指的数组元素的值取出,
使其增 1,
⑤若 p指向数组 a的第 i个元素:
*(p--) 与 a[i--],将 p 所指向的第 i个数组元素取出,然后使 p指向 i-1元素,
*(++p) 与 a[++i],先将 p增 1指向第 i+1个元素,然后取出第 i+1元素,
*(--p) 与 a[-- i],先将 p减 1指向第 i-1个元素,然后将其取出,
训练题:
1)对一整型数组 a[20]进行输入数值,输入值小于或等于零为止。
2)对上面的数组 a输出其中能被 2整除但不能被 3整除的数。
返回下一页上一页
10.3.3 数组名作函数参数
main( )
{ int array[10];

f(array,10);

}
f(int arr[ ],iny n)
{

}
返回下一页上一页数组名作函数参数
调用函数时,以数组名作实参时:
实际上是把数组的首地址传递给形参,此时,形参数组和实参数组占用的是同一段内存,在调用过程中,改变形参数组元素实际上也是改变实参数组元素,调用结束后,
虽然形参数组名不存在了,但对实参数组元素的操作效果已经形成了事实,
返回下一页上一页
T10-7.c 将数组 a中 n个整数按相反顺序存放 算法,
形参实参
M处于中间位置返回下一页上一页
T10-7.c 将数组 a中 n个整数按相反顺序存放 算法,
void inv (x,n)
int x[ ],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; }
return;
}
main( )
{ static int i,a[10]=
{3,7,9,11,0,6,7,5,4,2};
printf(“the original array:\ n”);
for(i=0;i<10;i++)
printf(“%d,”,a[i]);
printf(“\n”);
inv(a,10);
printf(“inverted array \n”);
for(i=0;i<10;i++)
printf(“%d,”,a[i]);
printf(“\n”);
}
返回下一页上一页形参改为指针变量
例 T10-7-1.c 将上例中形参 x[ ]改为指针变量的,以接收实参数组 a[ ]传递来的地址,再设指针 i,j,p 指向有关元素,以实现数组元素的转换,
返回下一页上一页例 T10-7-1.c
void inv(x,n)
int *x,n;
{ int *p,t,*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; }
return; }
main( )
{ static int i,a[10]=
{3,7,9,11,0,6,7,5,4,2};
printf(“the original array:\n”);
for(i=0; i<10; i++)
printf(“%d,”,a[i]);
printf(“\n”);
inv(a,10);
printf(“the inverted array \n”);
for(i=0; i<10; i++)
printf(“%d,”,a[i]);
printf(“\n”);
}
返回下一页上一页例 T10-8.c
从 10个数中找出最大值和最小值,并分别存入全局量 max,min中,在查找过程中指针:
p,依次指向数组元素,
array_end,指向最未元素后,
array:指向 array[0]所对应值,
返回下一页上一页
T10-8.c
int max,min;
void max_min_value(array,n)
int array[ ],n;
{ int *p,*array_end;
array_end=array+n;
max=min=*array;
for(p=array+1;
p<array_end; p++)
if(*p > max)
max=*p;
else if(*p<min)
min=*p;
return; }
main( )
{ int i,number[10];
printf(“enter 10 data\ n”);
for(i=0;i<10;i++)
scanf(“%d”,&number[i]);
max_min_value(number,10);
printf(“\ nmax=%d,
min=%d\ n”,max,min);
}
返回下一页上一页例 T10-8-1.c 对数组元素的操作过程中,形、实参数均使用指针变量。
int max,min;
void max_min_value(array,n)
int *array,n;
{ int *p,*array_end;array_end=array+n;
max=min=*array;
for(p=array+1; p<array_end; p++)
if(*p > max) max=*p;
else if(*p<min) min=*p; return;
}
返回下一页上一页例 T10-8-1.c 对数组元素的操作过程中,形、实参数均使用指针变量。
main( )
{ int i,number[10],*p ;
p=number;
printf(“enter 10 data\ n”);
for(i=0;i<10;i++,p++)
scanf(“%d”,p);
printf(“the 10 data,\ n”);
for(p=number,i=0; i<10; i++,p++)
printf(“%d,,*p);
p=number ; max_min_value(p,10);
printf(“\ nmax=%d,min=%d\ n”,max,min);
}
返回下一页上一页归纳:
在被调用函数中改变数组的值,实参、形参数的值,有四种情况:
( 1)实、形参都是数组名
( 2) 实参为数组名,形参为指针变量
( 3)形、实参都是指针变量
( 4)实参为指针变量,形参为数组返回下一页上一页例 T10-9.c 形实参都是指针变量,将数组 10个元素反序存放
void inv (x,n)
int *x,n;
{ int *p,m,t,*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;}
return;
}
main( )
{ int i,arr[10],*p=arr;
printf(“input array,\ n”);
for(i=0; i<10; i++,p++)
scanf(“%d”,p);
printf(“\n”);
p=arr ;
inv(p,10);
printf(“the inverted array,\n”);
for(p=arr; p<arr+10; p++)
printf(“%d,,*p);
printf(“\ n”);
}
返回下一页上一页例 T10-9-1.c 在主函数中不设数组,只设指针变量,
程序照样运行 (TC中是可以的 ),(P178)
main( )
{ int i,*arr;
printf(“&arr=%x,arr=%x\
n”,&arr,arr);
printf(“input 10 original data,\
n”);
for(i=0; i<10; i++,)
scanf(“%d”,arr+i);
printf(“\n”);
inv(arr,10);
printf(“the array has been
inverted:\ n”);
for(i=0; i<10;i++)
printf(“(arr+%d)=%x,*(arr+%d)
=%d\n”,i,(arr+i),i,*(arr+i));
}
void inv (x,n)
int *x,n;
{ int *p,m,t,*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;}
for(m=0 ; m<10; m++)
printf(“x+%d)=%x,*(x+%d)=
%d\n”,m,(x+m),m,*(x+m));
return;
}
返回下一页上一页例 T9-10.c 用选择法对 10个整数按从大到小顺序排列
main( )
{ int *p,i,a[10];
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);
p++; }
}
sort(x,n)
int x[ ],n;
{ int i,j,k,t;
for(i=0; i<n-1; i++)
{ k=i;
for(j=i+1; j<n; j++)
if(x[j] > x[k]) k=j;
if(k != i) { t=x[i];
x[i]=x[k];
x[k]=t;}
}
}
返回下一页上一页
10.3.4 指向多维数组的指针和指针变量一、多维数组的地址如定义,static int a[3][3]={ {1,3,2},
{5,7,4},
{9,11,8} };
a[0]+0 a[0]+1 a[0]+2
a[0] a a[0][0]=1 a[0][1]=3 a[0][2]=2
a[1] a+1 a[1][0]=5 a[1][1]=7 a[1][2]=4
a[2] a+2 a[2][0]=9 a[2][1]=11 a[2][2]=8
返回下一页上一页例 T10-10-2.c 二维数组元素的输出
main( )
{ static int i,j,
a[2][2]={1,3,5,7};
for(i=0; i<2; i++)
for(j=0; j<2; j++)
printf(“%d\n”,a[i][j]);
}
地址 数据表达方式
a+0,a[0],
*(a+0)+0,a[0]+0,
&a[0][0]
194→
1 a[0][0],*(a[0]+0),
*(*(a+0)+0)
*(a+0)+1,a[0]+1,
&a[0][1]
196 →
3 a[0][1],*(a[0]+1),*(*(a+0)+1)
a+1,a[1],
*(a+1)+0,a[1]+0,
&a[1][0]
198 →
5 a[1][0],*(a[1]+0),*(*(a+1)+0)
*(a+1)+1,a[1]+1,
&a[1][1]
19a →
7 a[1][1],*(a[1]+1),*(*(a+1)+1)
返回下一页上一页例 T101-10-2.c 二维数组元素及地址的输出
main( )
{ static int i,j,a[2][2]={1,3,5,7};
printf(“a=%x,a[0]=%x,a+0=%x\ n”,a,a[0],a+0);
printf(“a+1=%x,a[1]=%x,a[1]+0=%d\n”,a+1,a[1],a[1]+0);
for(i=0; i<2; i++) for(j=0; j<2; j++)
printf(“%x,%x,%x\n”,*(a+i)+j,a[i]+j,&a[i][j]);
for(i=0; i<2; i++) for(j=0; j<2; j++)
printf(“%d,%d,%d\n”,a[i][j],*(a[i]+j),*(*(a+i)+j));
}
返回下一页上一页二、多维数组的指针
1.指向数组元素的指针变量
例 T10-12.c 用指针变量顺序输出数组元素的值。
main( )
{ static int a[2][2]={1,3,5,7};
int *p;
for(p=a[0]; p< a[0]+4; p++)
printf(“p=%x,*p=%d\ n”,p,*p);
}
返回下一页上一页
2.指向包含 m个元素的一维数组的指针变量
①若 p是指向某数组的指针变量,则每当 p++时,
就指向下一元素 (因数组元素按先行后列顺序存放的 ),
②若 p是指向二维数组中只包含 m个元素的一维数组时 (即二维数组中的某一行 ),
此时的定义形式如,(* p)[2]
因此,p只能指向包含 2个元素的一维数组,
p的值是该一维数组的首地址,(每行看成是一维数组 )
p不能指向一维数组中的任一元素,某行第 j个元素只能通过 (*p)[j]访问,
返回下一页上一页例 T10-13.c 通过指向一维数组的指针变量 p,访问二维数组元素
main( )
{ static int a[2][2]={1,3,5,7};
int (*p)[2],i,j; p=a;
scanf(“i=%d,j=%d”,&i,&j);
printf(“a[%d][%d]=%d\ n”,i,j,*(*(p+i)+j));
p=p+0; printf(“a[0][1]=%d\n”,(*p)[1]);
p=p+1; printf(“a[1][0]=%d\n”,(*p)[0]);
}
返回下一页上一页例 10.14
有一个班,3 个学生,4门功课,计算总平均分,第 n
个学生的成绩
main()
{ void average();
void search();
static float score[3][4]=
{{65,67,70,60},
{80,87,90,81},
{90,99,100,98}};
average(*score,12);
search(score,2);
}
void average(p,n)
float *p;int n;
{ float *p_end;
float 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);
}
返回下一页上一页例 10.14
void search(p,n)
float (*p)[4];
int n;
{ int i;
printf(“the scores of no.%d are,\n”,n);
for(i=0;i<4;i++)
printf(“%5.2f,,*(*(p+n)+i));
}
还可以改写返回下一页上一页
§ 10.4 字符串的指针和指向字符串的指针变量
10.4.1 字符串的表示形式
字符串,用双引号括起的一串字符,
字符串可赋给字符型数组或指针变量,也可将字符数组或指向字符串的指针变量的值输出返回下一页上一页
T10-16.c 用字符数组和字符型指针变量输出字符串
main( )
{ static char s1[ ]=,I love china !” ;
static char *s2=,I love wuhan!” ;
printf(“s1=%s\ n”,s1);
printf(“s2=%s\ n”,s2); s2=s2+7;
printf(“s2=%s\ n”,s2);
}
返回下一页上一页例 T10-18.c 将字符串 a复制给 b(下标法 )
main( )
{ char a[ ]=,I am a boy.,,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”);
}
返回下一页上一页例 T10-19.c将字符串 a复制给 b(指针法 )
main( )
{ char a[ ]=,I am a boy.,;
char 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”);
}
返回下一页上一页
10.4.2 字符串指针作为函数的参数
例 10.20.1 用字符数组作形参
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("a=%s\n
b=%s\n"a,b);
copy-string(a,b);
printf("a=%s\n
b=%s\n"a,b);
}
返回下一页上一页例 10.20.2 用指针变量作形参
void copy-string(char *from,char *to)
{ for (; *from!='\0'; from++,to++)
*to=*from;
*to='\0';
}
Void copy-string(char *from,char *to)
{
while (( *from=*to)!='\0')
{ from++;
to++; }
}
void copy-string(char *from,char *to)
{
while (( *from++=*to++)!='\0');
}
例 10.20.3 简化的形式 1
例 10.20.3 简化的形式 2
返回下一页上一页
10.4.3 对使用字符指针变量和字符数组的讨论
1、字符数组是由若干个元素组成,每个元素中存放一个字符,而字符指针变量中存放的是地址,指针变量指向了这一字符串
2、赋值方式不同
char str[14];
str="I love china!";
char *a;
a="i love china!";
返回下一页上一页
10.4.3 对使用字符指针变量和字符数组的讨论
3、赋初值
char *a="I love china!";
char str[]="I love china!";
4,定义一个数组,在编译时为它分配了一批内存空间,它们有确定的地址,指针变量只分配一个数据类型的空间返回下一页上一页
10.5 函数的指针和指向函数的指针
10.5.1指向函数的指针
一个函数的包括一系列的指令,在内存中占据一片存诸单元,它也有一个起始地址,即函数的入口地址,通过这个地址可以访问这个函数,当一个指针变量指向函数入口地址,那么可以通过这个指针变量调用函数,那么该指针变量称为指向函数的指针变量,
定义,函数的数据类型 ( *指针变量名)();
例,int (*p)() ;
返回下一页上一页函数指针变量的作用
一个数组的起始地址是数组名,
一个函数的起始地址是函数名,
例,p=fun1;
一旦一个指针变量指向一个函数,访问函数指针变量的目标,其结果是使程序控制移至指针指向的地址,执行该函数的代码,
有了函数指针,使得函数也象数据一样可以在函数间传递。
返回下一页上一页
10.5.2 用指向函数的指针变量作为函数的参数
main()
{ int max(int x.int y);
int (*p)();
int a=10,b=30,c=0;
p=max;
c=(*p)(a,b);
printf("c=%d\n",c);
}
max( int x,int y)
{ int z;
if(x>y) z=x;
else z=y;
return z;
}
返回下一页上一页例,10.5.23 用函数指针调用求总数函数,
main()
{ int arr-add(int arr[],int n);
static int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int*p,total1,total2;
int(*pt)();
pt=arr-add;
p=a[0]; total1=arr-add(p,12);
total2=(*pt)(p,12)
printf(“total1=%d\n total2-%d\n”,total1,total2);
}
返回下一页上一页例,10.5.23 用函数指针调用求总数函数,
arr-add(int arr[],int n)
{inti,sum=0;
for(i=0,i<n;i++)
sum=sum+arr[i];
return(sum);
}
返回下一页上一页例,既可以检查字母又能检查数字相等
#include(stdio.h)
#include<stdlih.h>
#include<stdlib.h>
main()
{ int strcmp(); /* 字符串比较函数,系统提供 */
int numcmp(a,b); /* 数字比较函数 */
char *a,*b;
char sl[80],s2[80];
printf("Enter sting 1:\n");
get(s1);
printf("Enter sting 2:\n");
get(s2);
printf("number(n) or
alphabetic(a)?\n");
if(getchar()=='n')
check(s1,s2,numcmp);
else
check(s1,s2,strcmp);
}
返回下一页上一页例,既可以检查字母又能检查数字相等
check(a,b,cmp)
char*a,*b;
int (*cmp)();
{ printf(“testing for equality\n”);
if(! (*cmp)(a,b)) printf(“equality”);
else printf(“not equal”);
}
numcmp(a,b)
char *a,*b;
{ if( atoi(a)==atoi(b) )
return 0;
else return 1;
}
int isalpha(int ch)
原型在 ctype.h中,如果
ch是字母,则返回非零值,否则函数则返回零值。
int atoi(char *str)
原型在 stdlib.h中,将由
str所指向的字符串转换为整型值,若不能转换返回 0值。
返回下一页上一页传递函数名
普通的、简单的函数名传递是没有什么好处,然而当要传递任意函数给一些过程或需要函数数组时,就会显示出它的优越性,当编译程序时,语法分析程序 (用来检查算法表达式 )通常也要执行时各个程序的函数调用如正弦,佘弦,正切等函数,不必用复杂的 case语句来列出这些函数,可以用函数指针数组来调用对应函数。
在 C语言中设计指针函数指针的另一个目的是出自用 C
语言取代江编语言的需要,在汇编语言中,经常需要把某段程序的地址装入地址寄存器,然后通过地址调用这段程序。
在 C语言中使用函数指针可以实现同样的过程。
返回下一页上一页
10.6 返回指针值的函数
一个函数在被调用之后可以返回一个值。
若这个值是整型的,则称这个函数为整型函数。
若这个值是实型的,则称这个函数为实型函数
若这个值是字符型的,则称这个函数为字符型函数。
若这个值是一个地址,则称这个函数是指针型函数。
定义,数据类型,*函数名(参数列表);
返回下一页上一页例:编写一个 strchr函数,在一个字符串中找到一个 指定的字符,返回这个字符的地址。
char * strchr(char *str,char c1)
{ while (*str++! ='\0')
if( *str==ch ) return(str);
return (0);
}
main()
{ char *pt,ch,line[]=“i love china”;
ch='c';
pt=strchr(line,ch);
printf("这个 %c在字符串 %S中 ",*pt,line);
}
返回下一页上一页例:编写一个函数 strcat,将两字符串合并,并返回后字符串地址。
char * strcat(char*str1,
char*str2)
{ char *p1;
for(p1=str1;*p1!
='\0';p1++);
do{
*p1++=*str2++;
}while(*p2!='\0');
*p1='\0';
return(str1);
}
main()
{char string1[]="I have a
computer";
char string2[]="I learn c
language";
char *pt;
pt=strcat(string1,string2);
printf("新的字符串是 %s\n",
pt);
}
返回下一页上一页例 10.25 学生成绩
main()
{ score[][4]={{60,70,80,90},
{56,89,67,88},
{34,78,90,66}};
float
*search(float(*pointer)[4],int
n);
float *p;
int i,m;
printf("enter the number of
student:");
scanf("%d",&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);
}
返回下一页上一页
10.7 指针数组和指向指针的指针
10.7.1 指针数组的概念
一个数组,其元素均为指针变量,称为指针数组
指针数组的定义数据类型 *数组名 [数组长度 ];
int *p[4];
返回下一页上一页例 10.27将若干字符按字符顺序输出
main()
{ void sort(char *name[],int n);
void print(char *name[],int n);
char *name[]={"follow me","basic",
"great wall","fortran",
"computer design"};
int n=5;
sort(name,n);
print(name,n);
}
返回下一页上一页例 10.27将若干字符按字符顺序输出
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;}}
}
返回下一页上一页例 10.27将若干字符按字符顺序输出
vVoid print(char *name[],int n)
{ int I;
for (I=0;I<n; I++)
printf("%s\n",name[I]);
}
返回下一页上一页
10.7.2 指向指针的指针
定义:
int **p,*q;
int x=10;
q=&x;
p=&q;
printf("%d\n",**p);
p q x
&q &x 10
*p **p
返回下一页上一页例,10.28 使用指向指针的指针
main()
{ char *name[]={"follow me","basic",
"great wall","fortran",
"computer design"};
char **p;
int i;
for(i=0; i<5; i++)
{ p=name+i;
printf( "%s\n",*p);
}
}
返回下一页上一页
10.7.3指针数组作 Main函数中的参数
在操作系统状态下执行一个程序,必须键入泛程序的可执行文件和参数,这一行称为命令行。
例:命令名 命令行参数
copy file1.txt file2.txt 命令行返回下一页上一页指针数组作 Main函数中的参数
main( argc,argv)
int argc ;
char *argv[];
{
…………………
}
test prog1.c prog2.c /p
Argc=4
agrv[0]=“test”
argv[1]=“prog1.C”
Argv[2]=“prog2.C”
argv[3]=“/p”
int argc,是命令名和所有参数的个数之和
char *argv[],字符指针数组 argv[]的各个指针分别指向命令行中命令名和各个参数的字符串。
返回下一页上一页例
main(int argc,char*argr[])
{ int i;
printf("argc=%d\n",argc);
printf("命令名是 %s/\n,argv[0]);
for(i=i;i<argc;i++)
printf("参数 %d是 %s\n",i,argv[i]);
}
返回下一页上一页
10.8 指针数据小结
常用的指针类型变量归纳,
int *p,p为指向整型数据的指针变量
int (*p)[],p为指向含 n个元素的一维数组的指针变量
int(*p)(),p为指向函数的指针,该函数带回一个整型值 。
int *p[n],p定义为 n个元素的指针数组
int *p(),p指针型函数
int**p,p是一个指向指针的指针返回下一页上一页指针数据小结
指针的赋值
float f1;
float *p1=&f1;
float *p2=p1;
指针的运算
指针与整数相加减,(除了加减运算不允许有其他 )
指针与整数相加减,表示指针在内存空间向下上移动,移动以其数据类型长度为单位。
char*pc,c1[20]; pc=c1;
float*pf,a[20]; pf=a;
pc=pc+5; pf=pf+5;
返回下一页上一页
void指针
void指针:若不指定指针指向一个固定类型,它的定义为干 void *p;
表示:指针变量 p不指向一个确定的类型数据,而是用来存放一个地址。
返回下一页上一页
Turbo C动态分配函数
mallo()和 free()函数用于动态分配内存空间块
mallo()分配内存块并返回一个指向这个内存块的字符型指针。
free()用于释放原先所分配的内存块以便它能重复被分配。
一般形式,void *malloc(num-bytes);
free (void*p);
num-bytes,表示所需字节数目,若有足够多空间来满足所需要的内存块,返回这个块的首地址。若没有这么多空间返回零。
free(void*p) 用于释放经 malloc函数分配的有效的指针所指向内存块。
返回下一页上一页
Turbo C动态分配函数
例子,char *p;
p=(char*)malloc(1000);
例题:使用 size of来确定整型量所需有字节长度。
int*p;
p=(int*)malloc(50*sizeof ( int ));
分配内存要得保证它是有效分配,因为内存是有 限的。
因此:
if ( !p=malloc(100) )
{ printf("out memory\n");
exit(1);}
p指向了 1000个字节的空余内存块的首地址。
p指向了能存储 50个整型数据的内存块的首地 址,
返回下一页上一页例,数组空间的动态分配
在许多程序设计中,不可能知道数组需要占多大 的空间,例如文本编辑。
#include(conio.h)
#define N 4
#include(stdlib.h)
#define M 10
main()
{ int*p;
p=(int*)
malloc(N*M*sizeof(int));
if (!p)
{ printf("out memory\n");
exit(1);}
table(p); show(p);
}
Show(int p[N][M])
{ register int I,j;
printf("%10s %10s %10s
%10s\n",
"N","N^2","n^3","n^4");
for(j=1; j<11; j++){
for(i=1;i<5;i++)
printf("%10d",p[I][j]);
printf("\n"); }
}
返回下一页上一页数组空间的动态分配
Table( int p[4][10])
{ register int I,j;
for(j=1; j<11;j++)
for(I=1; I<5; I++)
p[I][j]=pwr(j,I);
}
pwr(int a,int b)
{ register int t=1;
for(; b; b--) t=t*a;
return k;
}
返回下一页上一页作业