C语言之路 第五章 函数与指针

第五章 函数与指针

我不愿有一个塞满东西的头脑,而宁愿有一个思想开阔的头脑----蒙田

对于许多问题的了解,很多人是在经意或不经意的情况下获得的。虽然人类具有智慧,但并不能单独完成所有的事情,必须要依赖于别人。你可能会请一个修理工来修理你的汽车,雇一个园丁来修剪你的草坪,或者需要一个仓库来存储每月的货物。对计算机程序(简单的程序除外)也会有完全类似地情形。它不能处理所有的工作,它需要一些其它独立的实体来代替它完成工作。在C语言中,这种实体称为函数。这一章中将研究这些函数。你会看到函数的许多不同特点,从最简单的函数开始,着力说明C语言函数强有力的功能。

5.1 什么是函数?

函数是一个独立的语句块,该语句块完成一个单一的任务。使用函数就好比你去雇一个人来为你完成某项特定的工作。与这个人打交道有时非常简单,有时又非常复杂。

看一个最简单的函数调用:

#include <stdio.h>

void message();

int main(void)

{

      message();

      printf("\nCry,and you stop the monotony!");

      system("pause");

}

void message()

{

      printf("\nSmile,and the world smiles with you...");

}

5.2 关于函数

    ●任何函数都可以被其他函数调用,甚至main()函数也可以被其他函数调用。

    ●函数可以被调用任意多次。例如:

    #include <stdio.h>

    void message();

    int main(void)

    {

        message();

        message();

        system("pause");

    }

    void message()

    {

        printf("\nJewel Thief");

    }

    ●程序中函数定义的顺序和函数被调用的顺序不需要完全相同。但是,切记,还是建议按照函数调用的顺序来进行函数的定义,这会程序易于理解。

    ●函数可以被另一个函数调用,但函数不可以在另一个函数中定义。例如:

    int main(void)

   {

     printf("\nI am in main");

     void argentina()

     {

          printf("\nI am in argentina");

          }

}这是错误的。

5.3 为什么要使用函数?

    ●写成函数可以避免反复书写相同的代码。

    ●通过使用函数,编写程序及跟踪程序所进行的操作会变得很容易。如果程序的操作可以分成一些独立的活动,而每一个活动都放在不同的函数中,于是可以独立地对每一个函数进行编写和检查。将代码分成函数模块,会使得程序更加容易设计和更易于理解。

5.4 在函数间传递值

/*通过键盘输入三个数,然后求这三个数的和*/

#include <stdio.h>

int calsum(int x,int y,int z);

int main(void)

{

      int a,b,c,sum;

     

      printf("\n输入a,b,c的值");

      scanf("%d%d%d",&a,&b,&c);

     

      sum=calsum(a,b,c);

      printf("\nsum=%d",sum);

      system("pause");

}

int calsum(int x,int y,int z)

{

     int d;

     d=x+y+z;

     return d;

}

下面是程序中值得注意的几点:

●变量a,b,c称为实参,变量x,y,z称为形参。传给被调函数的参数可以是任意数量,但形参和实参的类型、顺序及数量必须一致。

在被调函数中,也可以使用相同的变量名a,b,c来代替x,y,z。但编译器仍会将它们按不同的变量来处理,因为它们位于不同的函数中。

●在函数原型的声明中也可以不需要使用变量名。因此函数的原型也可以这样表示:

int calsum(int,int,int);

●return语句有两个作用:

   执行return语句时,会立即将控制返回到主调函数。

   ‚将return后面圆括号中的值返回给主调函数。

函数中return语句的出现次数是没有限制的。同时,return语句也并不总是一定要出现在被调函数的最后。如:

int fun()

{

     int n;

      printf("\nEnter any number");

     scanf("%d",&n);

     if(n>=10&&n<=90)

     return(n);

     else

     return(n+32);

}

●函数每次仅能返回一个值,因此下面的语句是非法的:

return(a,b);

return(x,12);

有一种方法可以不受这个限制,这个方法会在后面学习指针的时候再讨论。

●如果形参的值在被调函数中发生了改变,主调函数中实参的值不会发生改变。

5.5 函数调用约定

被调函数的形参和函数内定义的局部变量时内存中的堆栈创建的。当控制从函数返回时,堆栈就会被清空。有不同的函数调用约定。在所有的函数调用约定中,最常用的是标准函数调用约定。在这种调用约定中,参数按从右至左的顺序进行传递,堆栈由被调函数进行清空。

假设有如下形式的调用函数:

fun(a,b,c,d);

这种形式的函数调用,其参数的传递时从左至右还是从右至左无关紧要。但是,在有些函数调用中,参数传递的顺序是要重点考虑的。例如:

I nt a=1;

printf("%d%d%d",a,++a,a++);

令人惊讶的是,它输出的是3 3 1。这是因为C语言的调用约定是从右至左。

5.6 传值调用与传引用调用

调用函数,传递的是变量的值,称为传值调用。

若传递地址,那就是传引用调用。

5.7 指针简介

对初学者而言,C语言的哪一个特征最难理解呢?答案很容易:指针。其他的语言也有指针,但很少使用,没有像C语言这样对指针使用频繁。为什么呢?这是因为C语言可以灵活地使用指针,正是这一点才使C语言成为一门优秀的语言。

我想声明一个指针,并为它分配一些空间,但却不行,这样的代码有声明问题?

char *p;

*p=malloc(10);

因为这里声明的指针是p而不是*p。

5.8 /*通过传引用调用,让函数一次返回多个值*/

#include <stdio.h>

void areaperi(int,float *,float *);

int main(void)

{

      int radius;

      float area,perimeter;

      printf("\n输入半径:");

      scanf("%d",&radius);

      areaperi(radius,&area,&perimeter);

      printf("Area=%f",area);

      printf("\nPerimeter=%f",perimeter);

      system("pause");

      }

void areaperi(int r,float *a,float *p)

{

      *a=3.14*r*r;

      *p=2*3.14*r;

5.9 结论

●如果想让实参的值在被调函数中不发生变化,可以通过传值的方式传递实参。

●如果想让实参的值在被调函数中发生变化,就应通过传引用的方式传递实参。

●如果要求函数一次返回多个值,那么可以间接使用传引用调用来返回这些值。

5.10 递归

在C语言中,函数也可以调用自身。如果在函数体内的语句中,出现了函数调用自身的情况,则这个函数就称为递归。

/*用递归函数计算阶乘*/

#include <stdio.h>

int rec(int);

int main(void)

{

      int a,fact;

      printf("\nEnter any number");

      scanf("%d",&a);

      fact=rec(a);

      printf("输入这个数的阶乘为%d",fact);

      system("pause");

}

int rec(int x)

{

     int f;

     if(x==1)

     return(1);

     else

     f=x*rec(x-1);

     return(f);

初看起来,可能会觉得递归有点奇怪和复杂,但它通常是编写算法最直接的方式,而且一旦熟悉了递归,就会觉得它是最清晰的一种操作方式。

例题:

1,为变量n读取一个整型值,读取n个实数,找出其中的最大值和最小值

#include <stdio.h>

float maximum(float x,float y);

float minmum(float x,float y);

int main()

{

    int i,n;

    float max,min,x;

    printf("输入n的值:");

    scanf("%d",&n);

    printf("输入%d个值:",n);

    scanf("%f",&x);

    max=min=x;

    for(i=2;i<=n;i++)

    {

                     scanf("%f",&x);

                     max=maximum(max,x);

                     min=minmum(min,x);

                     }

    printf("最大值为%f\n",max);

    printf("最小值为%f\n",min);

    system("pause");

}

    float maximum(float x,float y)

    {

          if(x>y)

          return x;

          else

          return y;

          }

    float minmum(float x,float y)

    {

          if(x<y)

          return x;

          else

          return y;

          }

扩展阅读:关于函数

每个函数都应该设计得尽可能简单,简单的函数才容易维护。设计函数应遵循以下原则:

●实现一个函数只是为了做好一件事,不要把函数设计成用途广泛、面面俱到的,这样的函数肯定会超长,而且往往不可重用,维护困难。

●函数内部的缩进层次不宜过多,一般以少于4层为宜。若果缩进层次太多就说明设计得太复杂了,应考虑分割成更小的函数来调用。

●函数不要写得太长,建议在24行的标准终端上不超过两屏,太长会造成阅读困难,如果一个函数超过两屏就应该考虑分割函数了。但是如果一个函数在概念上是简单的,只是长度很长,这倒没关系。例如函数由一个大的switch组成,其中有非常多的case,这是可以的,因为各case分支互不影响,整个函数的复杂度只等于其中一个case的复杂度。

●执行函数就是执行一个动作,函数名通常应包含动词,例如: get_current、radix_tree_insert。

●比较重要的函数定义上方必须加注释,说明此函数的功能、参数、返回值、错误码等。

●另一种度量函数复杂度的办法是看有多少个局部变量,5到10个局部变量已经很多了,再多就很难维护了,应该考虑分割成多个函数。

●有的时候我们把函数叫做接口(Interface),调用函数就是使用这个接口,使用接口的前提是必须和接口保持一致。

●6 if else判断奇偶,可以把它分装成一个函数:

void print_parity(int x)

{

if (x % 2 == 0)

printf("x is even.\n");

else

printf("x is odd.\n");

}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值