c语言函数最大的作用,C语言函数完全攻略

C 语言强调模块化编程,这里所说的模块就是函数,即把每一个独立的功能均抽象为一个函数来实现。从一定意义上讲,C 语言就是由一系列函数串组成的。

在本章之前,我们的程序只有一个 main 函数,把所有代码都写在 main 函数中,这样虽然程序的功能正常实现,但显得杂乱无章,代码可读性、可维护性较差。学完本节之后,应把每个具体的独立功能单位均抽象为一个函数,在 main 函数中调用各个函数。

C 语言函数大概包括两种,一种是编译系统提供的库函数,如字符串处理复制函数 strcpy,这是 C 编译系统提供的库函数,该函数定义在 string.h 头文件中,在使用时必须包含对应的头文件,即需加上 #include 预处理包含命令;另一种是程序设计者自定义的函数。

每一个 C 语言程序都含有一个 main 函数,操作系统调用 main 函数,main 函数调用各个库函数或自定义函数。

函数的定义

函数是用户与程序的接口,在定义一个函数前,首先要清楚以下三个问题。

1) 函数的功能实现及算法选择。算法选择会在后续文章详细讲解,本节重点关注函数的功能实现。一般选取能体现函数功能的函数名,且见名知意,如求和函数的函数名可取为 add,求最大值的函数名可取为 max,排序函数可取名为 sort 等。

2) 需要用户传给该函数哪些参数、什么类型,即函数参数。

3) 函数执行完后返回给调用者的参数及类型,即函数返回值类型。

函教定义格式

函数定义的一般格式为:

返回类型 函数名 (类型参数1,类型参数2,…)

{

函数体

}

例如,定义一个求两个整数之和的函数,返回该和值。其函数实现代码为:

int add (int x,int y)

{

return (x+y) ; //括号可省略

}

说明:

1) 一个函数定义包含函数头和函数体两部分。函数名、参数表和返回类型这三部分一般称为函数头。一对大括号 {} 括起来的为函数体。

2) 函数名:符合标识符的命名规则,最好见名知意。如使用 add 作为求和函数的函数名,sort 作为排序函数名。

3) 参数表:函数定义时的参数又称为形式参数,简称形参。可以含有一个或多个参数,多个形参用逗号隔开。如下格式是错误的。

int add (int x;int y) //错误。函数各形参间用逗号隔开,而非分号

{

return x+y;

}

各形式参数对应类型均不能省略,如下格式也是错误的。

int add (int x,y) //错误。形参y的类型不能省略

{

return x+y;

}

也可以不含参数,不含参数时,参数表中可写关键字 void 或省略,为规范起见,教程中对没有参数的函数,参数表中统一写 void。例如:

类型 函数名 ()

{

函数体

}

等价于:

类型 函数名 (void) //建议的书写方式

{

函数体

}

4) 在函数定义中,参数表后不能加分号,如下函数定义格式是错误的。

float add (float x, float y); //错误。函数定义时,函数头后不能有分号

{

return x+y;

}

5) 函数体:即函数的功能实现代码部分。用一对大括号 {} 括起来,函数体也可以为空,即函数体内不含任何代码,便于以后扩充。例如:

void fun ()

{

}

6) 返回类型:也称为函数类型,即给调用者返回值的类型。要求显式指定返回类型。可以是基本数据类型如 int、char、float 等,也可以是复合数据类型,如数组类型、指针类型,或者是自定义类型(结构体类型)。

如果返回类型省略,一般默认为 int 型,但不推荐这种不规范的写法。

如果该函数没有返回类型,则为 void 类型。例如:

void add (int x,int y)

{

printf ("sum=%d\n", x+y);

}

除了 void 类型外,在函数体中,均需要显式使用 return 语句返回对应的表达式的值。

函教返回值

函数的值是指调用函数结束时,执行函数体所得并返回给主调函数的值。 关于函数返回值说明如下。

1) 带返回值的函数,其值一般使用 return 语句返回给调用者。其格式为:

return 表达式;

或者

return (表达式);

例如:

int add (int a, int b)

{

return (a + b); //return 后为表达式

}

2) 函数可以含一个或多个 return 语句,但每次调用时只能执行其中一个 return 语句。

例如,求整数绝对值的函数:

int f (int n) //含多个return语句,但每次调用只执行一个

{

if (n >= 0)

return n;

else

return -n; //或为 return (-1 * n);

}

3) 不带返回值的函数,其返回类型一般显式指定为 void 类型。如 void print_99 (void); 函数,其返回类型为 void。

4) 如果没有显式指定函数的返回类型,默认为 int 型,不推荐这种不规范的写法。 例如:

add (int a, int b) //省略返回类型,默认为int型

{

return (a + b);

}

5) return 后表达式的类型应与函数返回类型一致,如果不一致,则先将表达式的类型自动转换为函数类型后再返回。例如:

int f (void) //函数返回类型为int

{

int n = 1;

return (n + 2.3); //表达式为 double 型

}

上述函数中,函数类型为 int 型,return 后表达式的类型为 double 型值 3.3,两者类型不一致,故首先把表达式的类型 double 自动转换为 int 型值 3,然后再把 3 作为函数返回值返回给调用者。这种情况一般会丢失精度,可能得不到预想的结果。

函教调用格式

无参函数的调用格式

函数名();

注意:无参函数调用时,参数表空着,而不能写出 void,如下函数调用是错误的。

函数名 (void);//错误!无参函数调用时,参数表空着,不能加void

例如,设有定义好的无参函数 void print_99(void); 的调用如下。

print_99 ( ) ; //正确。调用无参函数

print_99 (void) ; //错误。实参表中不能加void

带参函数的调用格式

函数名(实参1,实参2,…);

说明:

1) 其中各实参可以是各种类型的常量、变量或表达式。例如,对定义好的带参函数 int add (int a,int b); 的调用如下。

add (2,5+1); //正确,实参可以为常量、变量或表达式 int n=7;

add(3,n); //正确,实参可以是变量

2) 调用函数时,不能写函数类型。

int add(2,3);//错误,调用时不能加返回类型

函教调用过程

函数调用的过程是:首先是实参给形参赋初值,接着函数体对形参做相应处理,最后把处理结果作为函数值返回给调用者。

未被调用时的函数形参并不占用内存空间,在函数调用时为形参变量分配空间,把实参的值赋给对应形参变量的空间,函数调用结束时,收回分配给形参的内存空间。即形参仅在函数调用的过程中占有内存空间。

通过如下 add 函数来说明函数调用过程。

//函数定义

int add (int a, int b)

int s;

s=a+b;

return s;

}

说明:

1) 以上是 add 函数的定义,a 和 b 为形参,s 为函数内定义变量,a、b、s 这三个变量均为局部变量,作用域为该函数,不能在 add 函数外使用。

2) 未调用 add 函数时,a、b 和 s 均不占用内存空间。函数调用时,即执行如下语句。

int x=2, y=3, sum;

sum=add(x,y);

该函数调用语句中,有两个实参,第一个实参为 x,其值为 2,第二个实参为 y,其值为 3。在函数调用时,为形参 a 和 b 及函数内变量 s 这三个整型局部变量分配存储空间,在 VC++ 6.0 里各占 4 个字节。函数调用时,实参与形参的关系如图 1 所示。

8494bfa8a0d1e5e43413956f4cf96a61.png

图 1

函数调用过程也就是实参给形参赋初值的过程,即:

a=x;

b=y;

函数体中,对形参 a 和 b 求和的结果赋给 s,最后把 s 的值作为函数的值返回赋给 sum 变量。调用过程结束,函数 add 中的所有局部变量的内存空间被收回。

由于形参仅在定义函数内有效,故在函数调用时,函数的实参可以和形参变量同名,互不影响。

函教原型声明

函数原型包括返回类型、函数名、参数列表等函数定义的基本信息。一般用于告知调用者该函数的基本信息,便于调用。

函数原型声明通常有以下两种形式。

无参函数原型声明格式为:

返回类型 函数名 (void);

或者

返回类型 函数名 ();

带参函数原型声明通常有如下两种形式。

1) 返回类型 函数名 (类型参数 1,类型参数 2,…);

这种写法是把函数定义时的函数头直接复制过来加分号即可,在编程时,操作方便,较节省时间,例如:

int add (int a, int b); //正确,函数头后面直接加分号

2) 返回类型 函数名 (类型,类型,…);

这种写法在第一种写法的基础上,去掉了各个形参名,只保留各个形参类型。这种写法比较专业,但可能多花费些时间。例如:

int add (int, int);//正确,只指明有两个整型形参即可

如果把函数定义的代码写在了调用语句之前,在这种情况下,虽然不加函数原型声明,也可以正常调用函数。但为了规范起见,要求所有定义函数,在函数调用前必须加函数原型声明语句。

比较常见规范的函数使用方式是:先函数原型声明,再调用,一般函数定义在程序的后面。

说明:函数原型声明,原则上只要在函数调用前声明都可以,但为了不让 main 函数显得臃肿,一般不放在main函数里面,比较规范的做法是把其放在 main 函数前面。本书采用这种方式。

函教调用举例

【例 1】带参函数调用举例。设计一个求两个整型数之和的函数。

问题分析:

1) 欲求两个整型数之和,调用者必须传递给该函数两个整型数,故函数需要两个整型类型的“容器”即形参,用于接收调用者传来的两个整型数。因实现功能为求和运算,函数名可取为 add,把求和的结果(整型)返回给调用者,即返回值类型也为整型。

2) 函数调用之前必须声明函数原型,一般放在 main 函数前面。

3) 函数调用时,把欲求和的被加数和加数作为实参传递给函数形参。

4) 函数的返回值即求和的结果,可以直接输出,或保存到某变量中参与其他运算或输出。

实现代码:

#include

int add (int a, int b); //函数声明

int main (void)

{

int a=2,b=3, s;

s=add(a,b); //函数调用,返回值赋给s

printf("%d+%d=%d\n",a,b,s);

return 0;

}

int add (int a, int b) //函数定义

{

int s;

s=a+b;

return s;

}

运行结果为:

2+3=5

【例 2】无参函数调用举例,编写一个打印九九乘法表的函数。

分析:该函数根据实现的功能可取名为 Print_99,该函数不需要调用者(main 函数)向其传递任何参数,该函数就可以正常打印九九乘法表,故该函数可以定义为无参类型。

实现代码:

#include

void print_99 (void);//函数声明

int main (void)

{

print_99();//无参函数调用

return 0;

}

void print_99 (void) //无参函数定义

{

int i, j;

for(i=1;i<=9;i++)

{

for (j=1; j<=i; j++)

printf("%d*%d=%d\t",i,j,i*j);

printf ("\n");

}

}

运行结果:

1*1=1

2*1=2   2*2=4

3*1=3   3*2=6   3*3=9

4*1=4   4*2=8   4*3=12  4*4=16

5*1=5   5*2=10  5*3=15  5*4=20  5*5=25

6*1=6   6*2=12  6*3=18  6*4=24  6*5=30  6*6=36

7*1=7   7*2=14  7*3=21  7*4=28  7*5=35  7*6=42  7*7=49

8*1=8   8*2=16  8*3=24  8*4=32  8*5=40  8*6=48  8*7=56  8*8=64

9*1=9   9*2=18  9*3=27  9*4=36  9*5=45  9*6=54  9*7=63  9*8=72  9*9=81

函数的嵌套调用

在 C 语言中,函数不能嵌套定义,即不能在一个函数中定义其他函数。例如,在 main 函数中嵌套定义函数 fun,为错误语法。

int main (void)

{

int fun(void)//错误,不能嵌套定义

{

//fun函数体

}

//...

return 0;

}

此代码就属于函数的嵌套定义,是错误的语法。

C 语言虽然不支持函数的嵌套定义,但支持函数的嵌套调用,即在一个函数中可以调用其他函数,在前面已经涉及函数嵌套调用,就是在main函数中调用其他自定义函数。自定义函数之间也可以相互嵌套调用。

【例 3】编程实现求 12+22+32+42+52+...+102 的值

实现代码为:

#include

int pow(int , int);

int sum(int);

int main(void)

{

int r;

r=sum(10);

printf("result=%d\n",r);

return 0;

}

int sum(int n)

{

int i,s=0;

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

{

s+=pow(i,2);

}

return s;

}

int pow(int m,int n)

{

int i,p=1;

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

{

p*=m;

}

return p;

}

运行结果为:

result=385

程序说明:该程序的执行过程是,操作系统调用 main 函数,main 函数调用 sum 函数,sum 函数调用 pow 函数,pow 函数执行完后,返回到其调用者 sum 函数,接着往下执行,sum 函数执行完,返回调用处 main 函数,接着往下执行,执行完 main 函数,return 0; 后返回给操作系统,整个程序执行结束。

另外,sum 函数及 pow 函数中均含有相同名字的变量 n 和 i。因为它们都是局部变量,作用域仅局限于各自的函数体中,故它们互不相干,互不影响。

传值调用和传址调用

C 语言中函数调用方式可分为传值调用和传址调用两大类。

传值调用

函数调用时,把实参的值传递给对应形参变量。这种调用形式,相当于形参复制了实参的一个副本,函数体内对形参(实参的副本)操作,形参变量的变化并不会影响到实参的值。即函数调用过程中,数据的传递是单向的。

传值调用时,传入的实参是普通变量(包括数组的某个元素)和常量及常量表达式。

例如,分析如下程序。

#include

void swap (int, int);

int main (void)

{

int a=3, b=5;

swap(a,b);

printf ("a=%d,b=%d\n",a,b);

return 0;

}

void swap (int x, int y)

{

int t;

t=x;

x=y;

y=t;

}

【运行结果】

a=3,b=5

程序分析:

形参为普通变量(整型),实参为普通变量(整型变量 a 和 b),故该函数调用为传值调用。形参相当于复制了实参的一个副本,函数内对形参的操作,均是对实参副本的操作,不会对实参变量产生任何影响。

另外,swap 函数中借助于变量 t,把形参 x 和 y 的值进行交换,由于 x、y 和 t 均属于 swap 函数内的局部变量,函数调用结束后,三个变量的空间全收回,对实参变量 a 和 b 没有任何影响。故调用该函数后,a 和 b 的值并未发生交换。

传址调用

实参是某个空间的地址,把该地址赋给形参变量,函数内对该地址操作,可间接对该地址所指的空间进行操作。即传址调用过程,函数可以通过传入的地址值,改变该地址空间的值。数组作为函数参数和指针作为函数参数均可实现址调用。

传址调用时,实参为地址(一维数组名被看成数组首元素的地址)。形参一般为数组类型或指针类型。如果形参为数组类型,则实参为同类型数组的数组名或首元素的地址。

例如,用数组类型作函数形参,编程实现求斐波那契数列的前 n 项的程序。实现代码为:

#include

#define N 10

void Fib (int x[], int n);

int main (void)

{

int i,a[N] = {0,1};

Fib(a,N);

for(i=0;i

printf ("%-4d",a[i]);

printf ("\n");

return 0;

}

void Fib (int x[], int n)

{

int i;

for(i=2;i

x[i]=x[i-1]+x[i-2];

}

运行结果:

0   1   1   2   3   5   8   13  21  34

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值