您的位置: 网站首页 > 程序开发 > C语言程序设计案例教程 > 第八章 指针 > 【8.3 指针与函数案例】

8.3 指针与函数案例

 

8.3  指针与函数案例

案例8.7  交换两个变量的值

【项目任务】

编写一个函数swap( ),功能是用来交换两个变量的值。

【设计思路】

编写一个交换两个变量值的函数。要达到交换两个变量值的目的,函数参数的传递必须采用地址传递的方法。在函数调用过程中,编译系统会将&a传给p1,则p1将指向变量a;同样,p2也会指向变量b,则*p1*p2将分别代表ab。在函数swap( )中交换ab的值,其实是交换主函数中ab的值。

【程序代码】

#include <stdio.h>

void swap(int *p1,int *p2)

{

    int temp;

 

/*交换*p1*p2的值,其本质是交换主函数中ab的值*/

    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);

}

案例8.8  一维数组中的最大元素

【项目任务】

编写一个函数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));

}

案例8.9  二维数组中的最大元素

【项目任务】

编写函数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));

}

案例8.10  对一维数组中的元素进行排序

【项目任务】

对一个一维数组中的元素进行排序。

【设计思路】

编写一个排序函数,将指针作为函数的形参,用来传递数组的首地址。排序算法有许多种,本案例采用的是选择排序法。

【程序代码】

#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;

    }

}

案例8.11  字符串大写函数

【项目任务】

编写一个函数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

案例8.12  字符串的复制

【项目任务】

编写一个函数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';

案例8.13  字符串的排序

【项目任务】

根据字符串的长度,对字符串进行从小到大的排序。

【设计思路】

使用选择排序的方法,根据字符串的长度,对字符串进行排序。利用指针数组来存储字符串的首地址。

【程序代码】

#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

【知识拓展】

1a为一个指针数组,即a是一个数组,有4个元素,每个元素的类型为指针类型。

2.使用指针数组来处理字符串比使用二维数组更能节省空间。

案例8.14  指向函数的指针

【项目任务】

编写一个程序,实现定义一个指针,使该指针指向一个函数的入口地址,然后利用指针调用该函数。

【设计思路】

首先定义一个函数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)对实体的引用,通常有两种方法:直接引用和间接引用。理解指向变量的指针,指向数组元素的指针,指向多维数组的指针,指向函数的指针。掌握指针作为函数参数、普通的指针变量,数组名作为函数参数和函数指针作为函数参数等常见应用。