【项目任务】
编写一个函数swap( ),功能是用来交换两个变量的值。
【设计思路】
编写一个交换两个变量值的函数。要达到交换两个变量值的目的,函数参数的传递必须采用地址传递的方法。在函数调用过程中,编译系统会将&a传给p1,则p1将指向变量a;同样,p2也会指向变量b,则*p1和*p2将分别代表a和b。在函数swap( )中交换a和b的值,其实是交换主函数中a和b的值。
【程序代码】
#include <stdio.h>
void swap(int *p1,int *p2)
{
int temp;
/*交换*p1和*p2的值,其本质是交换主函数中a和b的值*/
temp=*p1;*p1=*p2;*p2=temp;
}
void main()
{
int a=5,b=8;
swap(&a,&b);
printf("%d %d\n",a,b);
}
【运行结果】
8 5
【知识拓展】
1.参数传递有两种形式:一种是值传递;另一种是地址传递。地址传递就要求函数参数的类型为指针类型。
2.将以下两个程序与案例中的程序进行比较,思考为什么以下程序不能完成两个变量值的交换。
/*程序1*/
#include <stdio.h>
void swap(int *p1,int *p2)
{
int *temp;
temp=p1; p1=p2; p2=temp;
}
void main()
{
int a=5,b=8;
swap(&a,&b);
printf("%d %d\n",a,b);
}
/*程序2*/
#include <stdio.h>
void swap(int p1,int p2)
{
int temp;
temp=p1; p1=p2; p2=temp;
}
void main()
{
int a=5,b=8;
swap(a,b);
printf("%d %d\n",a,b);
}
【项目任务】
编写一个函数max( ),功能是求一维数组元素中的最大值。
【设计思路】
1.对于如何求最大值,举一个通俗的例子:假设桌上有10个苹果,要从其中挑选出一个最大的,这个例子和本案例程序的算法应该是一致的。最简单的做法是:先拿第一个苹果,然后从第二个苹果开始,直到最后一个苹果为止,将每个苹果和手中的苹果进行比较;如果发现比手中的苹果大,则丢到手中小的苹果,把大的苹果拿到手中。这样,将每个苹果都比较过后,就可以确定手中的苹果是最大的。以上所述即为求最大值的算法,归纳其步骤如下:
(1)将第一个数作为当前的最大值。
(2)从第二个数开始,直到最后一个数为止,将每个数与当前最大值进行比较,如果发现某个数比当前最大值大,则更新当前最大值,即把该数赋给当前最大值。
(3)当所有数都被比较完后,当前最大值就是所有数的最大值。
2.如果要求最小值,只须将以上算法改为;如果发现某个数比当前最小值小,则更新当前最小值,即把该数赋给当前最小值。
3.在程序中,分别用数组名和指针作为函数的实参和形参。
【程序代码】
#include <stdio.h>
int max(int *a,int n) /**a等价于a[]*/
{
int i;
int max_value;
max_value=a[0];
for(i=1;i<n;i++) /*因为指针a指向数组x,所以a[i]等价于x[i]*/
if(a[i]>max_value) max_value=a[i];
return max_value;
}
main()
{
int x[5]={10,20,30,40,50};
printf("%d\n",max(x,5));
}
【运行结果】
50
【知识拓展】
1.在本案例中,要注意三个问题。
(1)求最值的算法。
(2)实参x的值传给形参指针a,则a将会指向主函数中的x数组的首地址,从而很方便地利用a来处理数组x中的元素,即处理a[i]就相当于处理x[i]。
(3)形参a有两种写法:一种是指针形式;另一种是数组形式。需要注意的是,虽然可以将a写成数组的形式,但a不是数组,仍然是一个指针。
2.在以上案例中,除了参数采用指针的形式,其他部分是采用下标法来实现的,可读写性较强。此外,也可以完全采用指针法来实现以上案例,程序代码如下:
#include <stdio.h>
int max(int *a,int n)
{
int i;
int *p_max; /*定义用于指向当前最大值的指针*/
p_max=a;
for(i=1;i<n;i++)
if(*(a+i)>*p_max) p_max=a+i; /*更新指向当前最大值的指针*/
return *p_max;
}
main()
{
int x[5]={10,20,30,40,50};
printf("%d\n",max(x,5));
}
【项目任务】
编写函数max( ),功能是求二维数组元素中的最大值。
【设计思路】
本案例的算法与求一维数组元素中的最大值完全相同,只是函数的参数变成了指向二维数组的行指针。利用嵌套for语句循环遍历二维数组中的所有元素,并与当前最大值进行比较。
【程序代码】
#include <stdio.h>
int max(int (*a)[4]) /* *a等价于a[][4]*/
{
int i,j;
int max_value;
max_value=a[0][0];
for(i=0;i<3;i++)
for(j=0;j<4;j++)
if(a[i][j]>max_value) max_value=a[i][j];
return max_value;
}
main()
{
int x[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
printf("%d\n",max(x));
}
【运行结果】
12
【知识拓展】
在以上案例中,函数中的形参是一个指向拥有4个元素的数组的行指针,除了参数采用指针的形式,其他部分是采用下标法来实现的,可读写性较强。此外,也可以完全采用指针法来实现以上案例,程序代码如下:
#include <stdio.h>
int max(int (*a)[4])
{
int i,j;
int *p; /*定义用于指向当前最大值的指针*/
p=&a[0][0];
for(i=0;i<3;i++)
for(j=0;j<4;j++)
if(a[i][j]>*p) p=&a[i][j];
return *p;
}
main()
{
int x[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
printf("%d\n",max(x));
}
【项目任务】
对一个一维数组中的元素进行排序。
【设计思路】
编写一个排序函数,将指针作为函数的形参,用来传递数组的首地址。排序算法有许多种,本案例采用的是选择排序法。
【程序代码】
#include <stdio.h>
void print(int *a,int n) /*输出数组中的所有元素*/
{
int i;
for(i=0;i<n-1;i++)
printf("%d,",a[i]);
printf("%d\n",a[n-1]);
}
void sort(int *a,int n) /*对数组中的所有元素进行排序*/
{
int i,j;
int temp;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(a[i]>a[j])
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
main()
{
int x[5]={30,20,50,10,40};
sort(x,5);
print(x,5);
}
【运行结果】
10,20,30,40,50
【知识拓展】
常见的排序方法有选择排序,起泡排序和插入排序等,现在采用几种不同的排序方法重写函数sort( )。
/*起泡法*/
void sort(int *a,int n)
{
int i,j;
int temp;
for(i=0;i<n-1;i++)
for(j=0;j<n-1-i;j++)
if(a[j]>a[j+1])
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
/*选择法(另外一种写法)*/
void sort(int *a,int n)
{
int i,j,k;
int temp;
for(i=0;i<n-1;i++)
{
k=i;
for(j=i+1;j<n;j++)
if(a[j]<a[k]) k=j;
if(i!=k)
{
temp=a[i];
a[i]=a[k];
a[k]=temp;
}
}
}
/*插入法*/
void sort(int *a,int n)
{
int i,j;
int temp;
for(i=1;i<n;i++)
{
/*从a[i-1]开始,向a[0]方向扫描各元素,寻找适当的位置插入a[i]*/
j=i;
temp=a[i];
while(j>0 && temp<a[j-1])
{
/*当遇到temp>=a[j-1]结束循环时,j便是应插入的位置*/
/*当遇到j==0结束循环时,则0是应插入的位置*/
/*将元素逐个后移,以便找到插入位置时可立即插入*/
a[j]=a[j-1];
j--;
}
a[j]=temp;
}
}
【项目任务】
编写一个函数StrUpr( ),功能是将字符串中的所有小写字母转换成大写字母。
【设计思路】
使用指针指向字符串首地址,然后遍历字符串。如果发现指针所指向的字符为小写字母,则把该字符转换成大写字母,然后返回该字符串的首地址。
【程序代码】
#include <stdio.h>
char *StrUpr(char *s)
{
char *p;
p=s; /*指针p指向字符串首地址*/
while(*p) /*遍历字符串*/
{
if(*p>=’a’ && *p<=’z’) *p-=32;
p++;
}
return s; /*返回该字符串的首地址*/
}
main()
{
char str[20]="China";
printf("%s\n",StrUpr(str));
}
【运行结果】
CHINA
【知识拓展】
1.遍历字符串时,不要忘记语句p++;同时,循环条件也可以写成*p !=‘\0’。
2.大小写字母的ASCII码值相差32。
【项目任务】
编写一个函数mycopy( ),功能是实现字符串的复制。
【设计思路】
遍历字符串s2,将字符串s2对应的每个字符复制到字符串s1的对应位置,然后返回s1的首地址。当最后一个复制的字符为‘\0’时,循环结束。
【程序代码】
#include <stdio.h>
char *mycopy(char *s1,char *s2)
{
char *p;
p=s1;
while(*s1++=*s2++)
{
;
}
return p;
}
main()
{
char a1[20]="ABC";
char a2[20]="China";
printf("%s\n", mycopy(a1,a2));
}
【运行结果】
China
【知识拓展】
复制字符的循环结构也可以写成:
while(*s1++=*s2++);
或
while(*s2)
{
*s1=*s2;
s1++,s2++;
}
*s1='\0';
【项目任务】
根据字符串的长度,对字符串进行从小到大的排序。
【设计思路】
使用选择排序的方法,根据字符串的长度,对字符串进行排序。利用指针数组来存储字符串的首地址。
【程序代码】
#include <stdio.h>
#include <string.h>
main()
{
char *a[4]={"Changzhou","Wuxi","Suzhou","Shanghai"};
char *temp;
int i,j,k;
for(i=0;i<3;i++)
for(j=i+1;j<4;j++)
if(strlen(a[i])>strlen(a[j]))
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
for(k=0;k<4;k++)
printf("%s\n",a[k]);
}
【运行结果】
Wuxi
Suzhou
Shanghai
Changzhou
【知识拓展】
1.a为一个指针数组,即a是一个数组,有4个元素,每个元素的类型为指针类型。
2.使用指针数组来处理字符串比使用二维数组更能节省空间。
【项目任务】
编写一个程序,实现定义一个指针,使该指针指向一个函数的入口地址,然后利用指针调用该函数。
【设计思路】
首先定义一个函数max( )和一个指针变量p,使指针p指向函数max( ),通过指针p调用函数max( )。
【程序代码】
#include <stdio.h>
int max(int x,int y)
{
if(x>y) return x;
else return y;
}
main()
{
int (*p)(int x,int y); /*定义一个指向函数的指针p*/
p=max;
printf("%d\n",(*p)(5,8)); /*等价于printf("%d\n",max(5,8));*/
}
【运行结果】
8
【知识拓展】
指针不仅可以指向变量、单个数组元素、多个数组元素,还可以指向函数的入口地址。指向函数的指针通常被用做函数的参数,是C语言中比较高级的部分。
本章主要介绍了指针的基本概念和相关操作,并对指针与变量、数组、字符串和函数等之间的关联进行了介绍,其中重点要掌握以下两个方面:
(1)理解地址和指针的概念。指针是一种数据类型,处理的则是称为地址的一种数据。一个指针变量中如果存放一个实体的地址,通常形象地称为该指针变量指向该实体。实体可以是常量、变量、数组元素或函数等,这些实体均拥有自己的内存地址。
(2)对实体的引用,通常有两种方法:直接引用和间接引用。理解指向变量的指针,指向数组元素的指针,指向多维数组的指针,指向函数的指针。掌握指针作为函数参数、普通的指针变量,数组名作为函数参数和函数指针作为函数参数等常见应用。