函数定义
函数的定义就是函数体的实现。
函数体就是一个代码块,它在函数被调用时执行。
代码块就是一对花括号,里面包含了一些声明和语句(两者都是可选的)。
函数定义的语法如下:
类型 函数名(形式参数)
代码块
形式参数包括变量名和它们的类型声明。
代码块包含了局部变量的声明和函数调用时需要执行的语句。
return语句
当执行流到达函数定义的末尾是,函数就将返回(return)。
也就是说,执行流返回到函数被调用的地方。
return的语法如下:
return expression
表达式expression是可选的:
- 如果函数无需向调用程序返回一个值,它就被省略。
- 这些函数执行到函数体末尾时隐式地返回,它们没有返回值。
- 这种没有返回值的函数在声明时应该把函数的类型声明为void。
- 真函数时从表达式内部调用的,它必须返回一个值,用于表达式的求值。
- 这类函数的return语句必须包含一个表达式。
- 通常,表达式的类型就是函数声明的返回类型。
函数声明
我们需要向编译器提供函数的信息,以便编译器遇到一个函数调用时,编译器能够产生代码传递参数并调用这个函数,且接收该函数返回的值(如果有的话)。
通常,我们的方法是使用函数原型。
原型告诉编译器函数的参数数量和每个参数的类型以及返回值的类型。编译器见过原型之后,就可以检查该函数的调用,确保参数正确、返回值无误。当出现不匹配的情况是,编译器会把不匹配的实参或返回值转换为正确的类型,当然前提是这样的转换必须是可行的。
原型总结了函数定义的起始部分的声明。
如果一个函数的定义如下:
int *find_int(int key, int array[], int array_len)
{
for (int i = 0; i < array_len; ++i) {
if (array[i] == key)
return &array[i];
}
}
那么其函数原型如下:
int *find_int(int key, int array[], int array_len);
函数的默认认定
如果没有关于调用函数的特定信息,编译器便假定在这个函数的调用时参数的类型和数量正确的。
它同时会假定函数将返回一个整型值。
对于那些返回值并非整型的函数而言,这种隐式认定常常导致错误。
函数的参数
C函数的所有参数均已“传值调用”方式进行传递,这意味着函数将获得参数值的一份拷贝,这样,函数可以放心修改这个拷贝值,而不必担心会修改调用程序实际传递给它的参数。
所有参数都是传值调用。但是没如果被传递的参数是一个数组名,并且在函数中使用下标引用该数组的参数,那么在函数中对数组元素进行修改实际上修改的是调用程序中的数组元素。函数将访问调用程序的数组元素,数组并不会被复制。这个行为称为“传址调用”。
递归函数
递归函数就是直接或间接调用自身的函数。
对于递归函数而言,它在每次递归调用后必须越来越接近某种限制条件。
当递归函数符合这个限制条件时,它便不再调用自身。
#include <stdio.h>
void binar_to_ascii(unsigned int value)
{
unsigned int quotient;
quotient = value / 10;
if (quotient != 0)
binar_to_ascii(quotient);
putchar(value % 10 + '0');
}
int main()
{
binar_to_ascii(4267);
}
函数分析如下: