C Primer Plus(九)

第九章 函数

9.1 函数概述

汗舒适用于完成特定任务的程序代码的自包含单元。
为什么使用函数
一:函数的使用可以省去重复代码的编写。
二:函数使得程序更加模块化,从而有利于程序的阅读、修改和完善。
编写函数代码之前首先需要考虑的是函数的功能以及函数和程序整体上的关系。

9.1.1 函数示例

  1. #include<stdio.h>
  2. #define WIDTH 40
  3. void starbar(void);
  4. int main(void)
  5. {
  6. starbar();
  7. return 0;
  8. }
  9. void starbar(void)
  10. {
  11. int count;
  12. for(count=0;count<WIDTH;count++)
  13. putchar('*');
  14. putchar('\n');
  15. }

notice:
一:starbar标识符在不同位置被使用了3次:函数原型告知编译器其函数类型,函数调用导致该函数的执行,而函数定义则确切指定了该函数的具体功能。
二:函数同变量一样有多种类型。任何程序在使用函数之前都需要声明该函数的类型。函数后接分号表明该语句是进行函数的声明而不是函数的定义。
三:starbar()原型置于main()之前,也可以置于其内。
四:程序把starbar()和main()包含在同一个文件中,您也可以将它们放在不同的两个文件中。单文件形式比较容易编译,而使用两个文件则有利于在不同的程序中使用相同的函数。
五:starbar()中的变量count是一个局部变量。这意味着该变量只在starbar()中可用。

9.1.2 定义带有参数的函数:形式参量

可以对上树函数进行变化:

void show_n_char(char ch,int num)
{
int count;
for(count=0;count<WIDTH;count++)
putchar(ch);
}

void show_n_char(char ch,int num):通知编译器show_n_char()使用名为ch和num的两个参数,并且声明了它们的类型。ch和num被称为形式参数和形式参量,它们是局部变量是函数所私有的。
在函数原型中可以根据您的喜好省略变量名:void show_n_char(char,int);
函数调用中,通过实际参数对ch和num赋值。形式参量是被调函数中的变量,而实际参数是调用函数分配给被调函数变量的特定数值。
因为被调函数使用的值是从调用函数中复制而来的,所以不管在被调函数中对复制数值进行什么操作,被调函数中的原数值不会受到任何影响。
可以使用return从函数中返回一个值。
但函数返回值的类型和声明的类型不相同时会有什么结果呢?
实际返回值是当把指定要返回的值赋给一个具有所声明的返回类型的变量时得到的数值。
return语句的另一个作用是终止执行函数,并把控制返回给调用函数的下一个语句。

9.1.3 函数类型

函数应该进行类型声明。同时其类型应和返回值类型相同。而无返回值的函数应该被声明为void类型。在早期版本中,如果函数没有进行类型声明,则该函数具有默认的函数类型int。(C99不再支持)
函数声明需要在使用函数前进行。
函数声明只是将函数类型告诉编译器,而函数定义部分则是函数的实际实现代码。

9.1.4 函数原型

调用函数首先把参数放在一个成为堆栈的临时存储区域里,然后被调函数从堆栈中读取这些参数。
函数原型是对语言的有力补充。它可以使编译器发现函数使用时可能出现的错误或疏漏。

9.2 递归

C允许一个函数调用其本身。这种调用过程被称作递归。
递归一般可以代替循环语句使用,使得程序结构优美,但其执行效率却没有循环语句高。

9.2.1 函数示例

  1. #include<stdio.h>
  2. void up_and_down(int);
  3. int main(void)
  4. {
  5. up_and_down(1);
  6. return 0;
  7. }
  8. void up_and_down(int n)
  9. {
  10. printf("%d:n %p\n",n,&n);
  11. if(n<4)
  12. up_and_down(n+1);
  13. printf("%d:n %p\n",n,&n);
  14. }

每一级递归都使用它自己的私有变量n。调用是的地址和返回时的地址是相同的。
每一次函数调用都会有一次返回。当程序流执行到某一级递归的结尾处时,它会转移到前一级递归继续执行,是通过递归的每一级逐步返回。
递归函数中,位于递归调用前的语句和各级被调函数具有相同的执行顺序。
递归函数中,位于递归调用前的语句和各级被调函数具有相反的执行顺序。
虽然每一级递归都有自己的变量,但是函数代码并不会的得到复制。
递归函数中必须包含可以终止递归调用的语句。

最简单的递归形式是把尾递归语句放在函数结尾即恰在return语句之前。这种形式被称作尾递归或结尾递归。

9.2.2 递归的优缺点

优点:为某些编程问题提供了最简单的解决方法。
缺点:一些递归算法会很快耗尽计算机的内存资源。

9.3 多源代码文件程序的编译

9.3.1 UNIX

首先假定UNIX系统下安装了标准的UNIX C编译器cc。文件file1.c和file2.c中包含有C函数。下面的命令将把这两个文件编译在一起并生成可执行文件a.out
cc file1.c file2.c
将生成两个目标文件file1.o和file2.o
使用下列命令编译第一个文件并将其链接到第二个文件的目标代码。
cc file1.c file2.o

9.3.2 Linux

gcc file1.c file2.c
gcc file1.c file2.o

9.3.3 Windows

Windows系统下的编译器是面向工程的。工程描述了一个特定的程序所使用的资源。
运行多文件时,需要使用相应的菜单命令将源代码文件加入到一个工程之中。
如果把main()函数放在第一个文件中而把自定义函数放在第二个文件中实现,那么第一个文件仍需要使用函数原型。
如果把函数原型放在一个头文件中,就不必每次使用这些函数时输入其原型声明。

9.4 指针简介

指针是一个其数值为地址的变量。
int *ptr=& pooh; 把pooh的地址赋给ptr。ptr为一变量,而&pooh是一个常量。

9.4.1 间接运算符:*

对指针使用间接运算符,可以获取其指向地址存放的数值。

9.4.2 地址运算符:&

一元运算符&可以取得变量的存储地址。一个变量的地址可以被看作是该变量在内存中的位置。
%P是输出地址的说明符。

posted on 2013-06-05 07:04  颓废的悠然  阅读(334)  评论(0编辑  收藏  举报

导航