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
注意:gcc中数学库在libm.so
中,所以加上-lm
参数才能编译成功。有些头文件引用不需要-l
参数,因为他们已经包含在libc.so
中,gcc链接时会默认引入libc.so
。
实际上我们程序的入口函数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;
}
}