声明与定义
函数声明确定了一个函数的接口。函数被调用前必须有函数声明。
函数定义不能放在其它函数内,函数声明可以。
函数定义之外的声明中的形参列表的所有参数类型名必须与函数定义中的参数类型一致,但是生命的参数名可以不一样。实际上,函数定义之外的函数声明中的参数名是没有用处的。
函数定义与声明,实现代码如下:
#include <stdio.h>
void hello_world(void){ /*函数声明*/
int main(void){
hello_world(); /*函数调用*/
return 0;
}
void hello_world(void){ /*函数定义*/
priintf("Hello World!\n");
}
由于调用函数hello_world()之前未定义函数,因此,必须在前面加上函数声明。函数声明甚至可以放在main函数定义之后,如:
int main(void){
void hello_world (void);
hello_world();
return 0;
}
函数务必要在main函数之外声明。
函数值与形参列表
函数值类型:
int get_value(void);
double max(double num1,double num2);
char upletter(char c);
函数值类型不能是数组型,也不能是函数型。对于要返回数组型和函数型的函数值,可以用指针声明函数值类型。形式如下:
char * function(形参列表);
char *是一个char型的指针。
ping (int address) = int ping (int address)
使用数组型和函数型作为函数值类型,实现方法如下:
#include <stdio.h>
int hello_world(void)[20]{
printf("Helli World!\n");
}
int hello_ketty(void){
ptintf("Hello Ketty!");
}
int hello_mark(void){
printf("Hello,Mark!\n");
}
int main(void){
hello_mark();
return 0;
}
运行后,程序错误。
将数组类型int [20]作为函数返回值类型,是错误的。
将函数类型int (void)作为函数返回值类型,也是错误的。
将int型作为函数返回值类型,是正确的。
形参列表
1,形参列表的两种形式
作为函数定义一部分的函数声明中,形参列表必须为每个参数的生命类型和参数名。例如:
函数值类型 函数名(参数类型1,形参名1,参数类型2,形参名2… …);
而在函数定义之外的函数声明中,参数列表可以只列出参数类型,例如:
函数值类型 函数名(参数类型1,参数类型2,… …);
第一种声明形式中所有形参名是无意义的,检查函数合法性时无需匹配原型和定义的形参名。
虽然声明中的函数名没有实际的意义,但是在定义外声明函数时,为了提高程序的可读性,建议使用带参数名的声明方式。
void copy_value(int des,int src); /*des一般为destination的简写,src为source的简写*/
void copy_value(des,src);
如果形参的类型不同,不能像声明普通变量一样在一个声明表达式中声明多个变量。
void copy_value(int des,src);
这是错误的声明方法。
2,使用空列表
参数列表也可以是空的,表示没有参数。例如:
int hello_mark(void)
也可以写为:
int hello_mark()
要声明一个无形参的函数时,建议使用void型作为函数列表内容,以显示地说明不需要参数。
3,实参到形参的值传递
调用函数后,每个形参都初始化为相对应的实参,如下所示:
参数类型1 形参1 = 实参1;
参数类型2 形参2 = 实参2;
…
进行这样的初始化之后,形参值的改变影响不了实参。例如,对print_data的声明和调用如下所示:
void print_data(const int a,const int b)
print_data(x,y)
调用后实参和形参的值传递传递过程可以理解为:
const int a = x;
const int b = y;
然后,执行print_data的函数体代码。示例代码如下:
#include <stdio.h>
void increase(int x,int y,int z){
/*打印自增前的形参值*/
printf("Before increment in function:\n");
printf("x = %d,y = %d,z = %d\n",x,y,z); /*输出 x , y , z 的值*/
++x;
++y;
++z;
/*打印自增后的形参值*/
printf("After increment in function:\n");
printf("x = %d,y = %d,z = %d\n",x,y,z); /*输出 x , y , z 的值*/
}
int main(void){
int a = 3;
int b = 4;
int c = 5;
/*打印调用函数前的形参值*/
printf("Before calling increase():\n");
printf("a = %d,b = %d,c = %d\n",a,b,c);
/*调用increase函数*/
increase(a,b,c); /*调用increase函数*/
/*打印调用函数后的实参值*/
printf("After calling increase():\n");
printf("a = %d,b = %d,c = %d",a,b,c); /*输出a,b,c的值*/
return 0;
}
运行结果如下:
![图片有点大,传不上去](https://img-blog.csdnimg.cn/20191027233806337.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0hFTVZFUg==,size_16,color_FFFFFF,t_70)
4,函数返回值
当函数返回值类不为void型时,函数返回值就可以作为函数调用表达式中的一个操作数来使用。一个函数的函数值一般有两种用途:
(1)信息载体
函数可以使用return语句将函数内的某个值带到函数外,如果需要返回的信息需要一个数值来传递,那么,可以选择这个信息作为返回值带到函数外。下面是把两个返回值作为信息载体的例子:
#include <stdio.h>
/*计算一个数的立方*/
int cube(const int x){
return x * x * x; /*返回x的立方*/
}
/*计算一个数的阶乘*/
int factorial(int x){
int rst = 1;
for( ; x > 0; --x){ /*计算x的阶乘*/
rst *= x;
}
return rst; /*返回x的阶乘*/
}
int main(void){
const int v = 7;
printf("cude(7) = %d\n",cube(v)); /*将cube的函数值作为printf函数的参数*/
printf("factorial(7) = %d\n",factorial(v)); /*将cube的函数值作为factorial函数的参数*/
return 0;
}
(2)只是指示执行状态
当函数执行有多个分支,而函数外部有需要知道函数执行的是哪一个分支时,可以在函数内部使用一个标志变量来记录执行的分支,最后使用return语句将该值返回。在函数外部,通过检查该标志的值,就可以判断函数执行了哪一个分支。以下是程序的代码:
#int mult_operation(形参列表){
int flag = -1;
if(condition1){
第一个操作分支;
flag = 1;
}
else if(condition2){
第二个操作分支;
flag = 2;
}
else if ...{
...
}
else if(condition N){
第N个操作分支;
flag = N;
}
return 0;
}
上述程序中,在函数内部定义一个变量flag,执行分支n就将flag设为n,最后,把flag值返回。在函数外部通过检查函数值,即flag的值,就可以判断函数内部执行的是哪一个分支。
还有一种情况也需要把返回值当做标志用。当函数的执行有可能出现异常和错误时,也需要有一个标志变量来指示函数的执行状况,最后,可以把这个标志变量作为返回值返回。同样,在函数外部检查该标志的值,就可以判断函数的执行情况。以下是示例伪代码:
int function(形参列表){
/*判断异常情况1*/
if(condition1){
打印异常信息
return -1;
}
... ...
/*判断异常情况2*/
if(condition2){
return -2; /*如果与前一种异常情况相似,可以同样返回-1*/
}
... ...
return 0; /*函数成功执行*/
}
在数组中查找目标数使用函数值来判断是否存在,实现代码如下:
#include <stdio.h>
#define MAX_SIZE 8
const int ture = 1;
const int flase = 0;
/*检查一个数组中是否存在目标数*/
int search_data(const int array[ ],const int size,const int target){
int i = 0;
/*遍历数组查找*/
for(i = 0;i < SIZE; ++i){
if(target == array[i])
return ture;
}
return flase;
}
int main(void){
int q[MAX_SIZE] = {7,5,0,89,12,4,31,54}; /*定义并初始化q*/
int x = 0;
int i = 0;
printf("Elements in this array:\n"); /*输出数组个元素*/
for(i = 0;i < SIZE; ++i)
printf("%4d",q[i]);
printf("\nPlease input the target number:\n");
gets(x); /*为x赋值*/
/*根据返回值结果,得到查找的结果*/
if(true == search_data(q,MAX_SIZE,x){
printf("%4d exists in this array.\n")
}
else if{
printf("Can noy find %d in this array.\n")
}
return 0;
}
(5)函数体
函数体可以为空,函数体为空的函数什么都不做,不会执行任何操作。例如:
void createBotton(const int name,int flag)
{
}
函数体的变量定义。
例如:
int get_max(const int a[SIZE][SIZE]){
int i ,j;
int max = a[0][0];
for(i = 0;i < SIZE; ++i){
for(j = 0;j < SIZE; ++j){
if(max < a[i][j])
max = a[i][j];
}
}
return 0;
}
检查形参
int deal_element(int array[SIZE],int index){
if(index >= SIZE || index < 0){ /*检查形参*/
printf("Error index when get_ele().\n"); /*打印提示信息*/
return -1; /*返回错误*/
}
/*对array[index]进行操作*/
...
return 0;
}
在函数deal_element使用数组前,对index进行检查可以防止访问到数组外的空间,避免一些错误。例如,做一个除法运算时,要求除数不能为,示例代码如下:
int div(const int x,const int y){
if(0 == y){
printf("Error:can not be a divisor.\n");
return -1;
}
printf("x / y = %d\n",x / y);
return 1;
}
return语句
return语句的功能是计算返回值,并结束函数。return语句一般由关键字return和表达式两部分组成,如下:
return 表达式;
执行该语句时,先计算表达式的值,该值作为函数返回值,再结束函数。如果返回类型时void型,return语句可以省略。
向上取整合向下取整,示例代码如下:
#include <stdio.h>
int floor_new(const double d){
return d; /*返回double型,将自动转换为int型*/
}
/*向上取整*/
int celling_new(const double d){
int f = floor(d); /*调用floor函数*/
return d == f ? f : f + 1; /*将自动转换为floor型*/
}
int main(void){
double data;
printf("Please input a double number:\n");
scanf("%lf",&data);
printf("floor(%f) = %d\n",data,floor_new(data)); /*调用floor_new函数*/
printf("celling(%f) = %d\n",data,celling_new(data)); /*调用celling_new函数*/
return 0;
}
函数celling_new的功能是对参数向上取整,即得到大于或等于该参数的最小整数。由于return语句的表达式为:
d > f ? d + 1 : d
其中,d和d + 1都是double型,所以return语句的返回值为double型,但是函数声明中函数值的类型为ing型,因此,double型的return值会转换为int型后再返回。在程序中,celling_new函数先调用floor_new函数对double型形参d向下取整,得到d的整数部分f。按照上述的分析,函数celling_new也可以直接返回int型,无需类型转换,如下所示:
int celling_new(const double d){
int f = floor(d);
return d == f ? d + 1 : d;
}
main函数
main函数的声明如下:
int main(void)
int main(int argc,char * argv[ ])
声明main函数时,只能将函数值定义为int型。