当前所在位置:珠峰网资料 >> 计算机 >> 软件水平 >> 正文
程序员之程序设计知识点十一
发布时间:2010/6/2 15:30:42 来源:城市学习网 编辑:ziteng
  6.4 函数调用中的数据传递方式
  函数调用时,调用处与被调用函数之间会有数据传递发生。在C程序中,函数调用的数据传递方式有四种:实际参数的数据值传递给形式参数(值传递方式)、实际参数的指针值传递给形式参数(地址传递方式)、函数以返回值传递给调用环境(返回值方式)、调用环境与被调用函数共用全局变量(全局变量传递方式)。在地址传递方式中,实际参数可以是传递一般变量的指针、数组某元素的指针、字符串某字符指针等。
  1.实际参数向形式参数传递非指针数据
  调用带形式参数的函数时,调用处将实际参数的值传递给被调用函数的形式参数。在此要特别说明以下几点:
  (1)函数调用时实际参数为对应的形式参数提供初值,实际参数表达式的值是在执行函数体之前计算的,函数调用中的实际参数可以是常量、变量或是一般的表达式。
  (2)C语言规定,实际参数表达式对形式参数的数据传递是“值传递”的,是单向传递。如实际参数也是变量,则实际参数变量与形式参数是不同的变量,实际参数变量的值传给形式参数,而不能由形式参数直接传回给实际参数。在函数执行过程中,形式参数变量的值可能被改变,但这改变对原先与它对应的实际参数变量没有影响。
  2.实际参数向形式参数传递指针
  实际参数向形式参数传递变量的指针
  函数可以设置指针类型的形式参数,调用带指针类型形式参数的函数时,对应指针形式参数的实际参数必须是相同类型的指针(如胡同类型的某变量的指针),指针形式参数变量从实际参数处得到某变量的指针。指针形式参数对于函数来说有特别的作用,它使函数得到了调用环境中某变量的地址,函数就可用这个地址间接访问函数之外的变量。因此,指针类型形式参数为函数改变调用环境中的数据对象提供了手段。
  如希望函数能通过形式参数改变任意指定变量的值,需要在三个方面协调一致:
  (1)首先,函数应设置指针类型的形式参数;
  (2)其次,函数体必须通过指针形式参数间接访问变量,或引用其值或修改其值;
  (3)最后,调用函数时,要以欲改变值的变量的指针为实际参数调用函数。
  实际参数向形式参数传递数组元素的指针
  为了能使函数处理不同的成组变量,应向形式参数传递数组元素的指针,最通常的情况是数组首元素的指针。由于数组名能代表数组首元素的指针,所以常用数组名实际参数给形式参数传递数组首元素的指针。例如,用于求数组前n个元素和的函数sun(),这个函数被正确地设置有两个形式参数:一个形式参数是数组元素的指针;另一个整型的形式参数用于指定求和数组的元素个数。
  【例6.2】求数组元素和的函数。
  int sum( int *a, int n)
  { int i, s;
  for(s=i=0; i< n; i++)
  s+=a[i];
  return s;
  }
  利用函数sum(),如有以下变量定义:
  int x[]= {1, 2, 3, 4, 5 }, i, j;
  则语句
  i=sum(x,5); j=sum(&x[2],3);
  printf(“i=%d\n j=%d\n”, i,j);
  将输出:
  i=15
  j= 12
  函数调用sum(x,5)将数组x的首元素地址(&x[0])传送给形式参数a;函数调用sum(&x[2], 3)将数组x的元素x[2]的地址(&x[2])传送给形式参数a,而x[2]的地址就是数组元素段x[2]、x[3]、x[4] 的开始地址。
  为了明确指明形式参数是数组元素的指针,形式参数的类型可以指定为数组类型的。如改写后的函数sum()定义如下:
  int sum(int a[], int n)
  {int i,s;
  for(s= i=0; i
  s+=a[i] ;
  return s;
  }
  对于数组类型的形式参数来说,函数被调用时,与它对应的实在数组由多少个元素是不确定的,可能会对应一个大数组,也可能会对应一个小数组,甚至会对应数组中的某一段。所以在数组形式参数说明中,形式参数数组不必指定数组元素的个数。任何数组形式参数说明:
  类型 形式参数名[ ]
  都可改写成:
  类型 *形式参数名
  函数形式参数也是函数的一种局部变量,指针形式参数就是函数的指针变量,函数sum()的定义又可改写成如下形式:
  int sum(int *a, int n)
  { int s=0;
  for(; n--;)
  s+=*a++;
  return s;
  }
  实际参数向形式参数传递字符串某字符的指针
  这种情况要求形式参数为字符指针的,对应的实际参数是字符数组某个元素的指针,通常是字符串的首字符指针。由于字符率是用一维的字符数组来实现的,所以字符指针形式参数与指向数组元素指针形式参数有相同的使用方法。但因字符串的特殊性,在编写字符串处理函数时还会有许多技巧。下面以字符串拷贝函数strcpy()的实现为例说明字符指针形式参数的用法。
  【例6.3】字符串拷贝函数strcpy()。
  该函数功能是将一个已知字符串的内容复制到另一字符数组中。拷贝函数设有两个形式参数from,to。from为已知字符串的首字符指针,to为存储复制字符串首字符指针。函数定义如下:
  void strcpy(char *to, char *from,)
  {
  while( *to++=*from++);
  }
  3.调用环境与函数共用全局变量
  为了减少函数的形式参数,或因若干函数必须共同对一组变量进行处理。可让调用环境与被调用的函数共用一组变量。即在函数调用之前先给变量设置初值,函数对这些变量进行处理,并将处理结果留在全局变量中。由于这种使用方式函数之间相互影响太大,如程序有错,就会很难修正。 [NextPage]   6.5 返回指针的函数
  函数也可以返回指向某种数据对象的指针值。定义(或说明)返回指针值函数的函数头有以下形式:
  类型说明符 * 函数名(形式参数表)
  例如,函数说明:
  int *f(int,int);
  说明函数f()返回指向int型数据的指针,该函数有两个整型形式参数。
  在函数名的两侧分别为* 运算符和()运算符,而()的优先级高于*,函数名先与()结合。函数名()是函数的说明形式。在函数名之前的* ,表示此函数返回指针类型的值。
  【例6.4】 编制在给定的字符串中找特定字符的第一次出现。若找到,返回指向字符串中该字符的指针;否则,返回NULL值。
  设函数为search(),该函数有两个形式参数,指向字符串首字符的指针和待寻找的字符。以下是函数search()的定义:
  char *search(char *s,char c)
  { while(*s && *s! = c)
  s++;
  return *s?s:NULL;
  }
  6.6 函数递归调用
  一个函数为完成它的复杂工作,可以调用其它别的函数。例如,从主函数出发,主函数调用函数A() ,函数A()又调用函数B(),函数B()又调用函数C(),等等。这样从主函数出发,形成一个长长的调用链,就是通常所说的函数嵌套调用。函数嵌套调用时,有一个重要的特征:先被调用的函数后返回。如这里所举例子,待函数C()完成计算返回后,B()函数继续计算(可能还要调用其它函数) ,待计算完成,返回到函数A(),函数A()计算完成后,才返回到主函数。
  当函数调用链上的某两个函数为同一个函数时,称这种函数调用方式为递归调用。通过速归调用方式完成其功能的函数称为递归函数。许多问题的求解方法具有递归特征,用递归函数描述这种求解算法比较简洁。计算n的阶乘(n!)函数就是一个很好的例子。因
  n! = l*2*3* …*n
  按其定义用循环语句可以方便地实现,写成函数见下例6.5。
  【例6.5】用循环实现阶乘计算的函数。
  float fac(int n)
  {float s;
  int i;
  for(s=1.of,i=l;i<=n; i++)
  s*=1;
  return s;
  }
  然而,把n! 的定义改写成以下递归定义形式
  (1)n!=1, n<=l;
  (2)n!= n*(n-1)!, n>l。
  根据这个定义形式可用递归函数描述如下例6.6。
  【例6.6】 用递归实现阶乘计算的函数。
  float rfac(int n)
  {
  if( n<=1) return 1.0f;
  return n*rfac(n-1) ;
  }
  以计算3!为例,说明递归函数被调用时的执行过程。设有代码m= rfac(3) 调用函数rfac()。函数调用rfac(3) 的计算过程可大致叙述如下:
  以函数调用rfac(3) 去调用函数rfac() ;函数rfac(n=3) 为计算3*2! ,用rfac(2) 去调用函数rfac();函数rfac(n=2) 为计算2*1!,用rfac(1)去调用函数rfac();函数 rfac(n=1) 计算1! ,以结果1.0返回;返回到发出调用rfac(1) 处,继续计算,得到2! 的结果2.0返回;返回到发出调用rfac(2) 处,继续计算得到3! 的结果6.0返回。
  递归计算n! 有一个重要特征,为求n有关的解,化为求n-l的解,求n-1的解又化为求n-2的解,如此类推。特别地,对于1的解是可立即得到的。这是将大问题解化为小问题解的递推过程。有了1的解以后,接着是一个回溯过程,逐步获得2的解,3的解,……,直至n的解。
  【例6.7】 用递归函数实现数组元素的求和计算。
  要采用递归方法计算数组元素的和,可把数组元素的累计和等于当前元素与数组其余元素的和,而对数组其余元素的和通过递归实现。下面的函数定义是这样的解法之一。
  int rsum(int *a, int n)
  {
  if( n==0) return 0;/*若数组没有元素,则返回0*/
  return *a+rsum(a+l,n-1);/*当前元素与其余元素的和*/
  }
广告合作:400-664-0084 全国热线:400-664-0084
Copyright 2010 - 2017 www.my8848.com 珠峰网 粤ICP备15066211号
珠峰网 版权所有 All Rights Reserved