函数
C语言中函数分为库函数和自定义函数。C语言包含一组标准库,Linux操作系统下其实现为glibc(GNU C Library),大部分函数位于共享库文件libc.so.6,除此之外我们也可以引用其他人开发的函数库,自定义函数则来自于自己的代码。
标准库函数
我们可以通过引用标准库头文件调用标准库函数,例如数学函数包含在math.h头文件中,下面例子代码调用了标准库函数sin()。
#include <stdio.h>
#include <math.h>
int main(void)
{
double pi = 3.1416;
double result = sin(pi / 2);
printf("%f\n", result);
return 0;
}
编译程序。
gcc demo.c -lm
运行结果如下。
1.000000
注意:由于一些历史原因,数学相关函数在libm.so中而未合并在libc.so.6内,所以使用GCC编译时我们需要加上-lm参数才能编译成功。而大多数标准库的头文件引用不需要-l参数,因为他们已经包含在libc.so.6中,GCC链接时会默认引入它。
自定义函数
实际上我们程序的入口函数main(void)就是自定义函数。
不带参数的函数,参数列表应写成void(c99标准)。实际上main函数还可以接收命令行参数,因此也可以写成main(int argc, char *argv[]),没有用到这些参数时则推荐写成void。
main函数执行成功应该返回0,失败返回非0,该返回值可以在执行程序后,在Shell中用echo $?命令查看。
自定义函数例子。
#include <stdio.h>
void show(void);
int main(void)
{
show();
show();
return 0;
}
void show(void)
{
printf("hello\n");
}
在实际开发中,我们应该适当的使用函数封装代码,函数能够复用,使得代码更加简洁。
C语言中,函数应该遵循先声明后使用的原则,尽管我们也可以在main函数前直接定义,但先声明再定义更加规范。此外,函数声明可以在另一个函数中,但不允许函数嵌套定义。
函数参数
函数声明和定义中使用的参数被称为形参,具体调用函数时传入的参数被称为实参。
#include <stdio.h>
void print_time(int h, int m);
int main(void)
{
print_time(12, 59);
return 0;
}
void print_time(int h, int m)
{
printf("%d : %d\n", h, m);
}
变量作用域
一个函数中的变量不能在外部被引用,函数被调用时,会临时在栈上分配空间存放变量;定义在函数外面的变量则是全局变量。全局变量如果和局部变量重名,在局部变量作用域内会被局部变量覆盖。
全局变量使用时的注意点:
double pi = 3.14 + 0.0016; //合法的全局变量初始化
double pi = acos(-1.0); //不合法的全局变量初始化
int minute = 360;
int hour = minute / 60; //也不合法
C语言规定全局变量必须用常量表达式初始化。全局变量可能在多处调用,因此必须以固定的值来初始化,实际上全局变量初始值必须由编译器计算并包含在代码段中,因此调用函数初始化全局变量是不行的,局部变量却可以这样做。
返回值
函数的返回值使用return声明。下面例子函数中,返回传入参数是奇数还是偶数。
int is_even(int x)
{
return !(x % 2);
}
递归函数
函数自己调用自己叫递归,递归函数通常有一个递归出口。递归和带栈迭代是等价的,递归代码更加简洁,容易理解,但是程序栈的高度不好控制。下面是一个递归函数的例子。
int factorial(int n)
{
if (n == 0)
return 1;
else
{
int recurse = factorial(n-1);
int result = n * recurse;
return result;
}
}