C语言学习之函数
函数用于将一个大任务分割成若干个较小任务,最常见的就是main函数,main函数是整个程序的入口。
关于main函数的写法,C标准定义了两种写法:
如果不带参数可以这样写
int main(void) { /* ... */ }
如果带参数一般这样写
int main(int argc, char *argv[]) { /* ... */ }
argc表示参数的个数,argv为参数列表。
一个设计的恰当的函数应该屏蔽具体设计细节,只留出相应接口,这样也便于维护。
1. 按值传递
一个函数包括参数列表和一个返回值,但是在操作函数时请注意,函数参数都是按值传递的。
void swap(int a, int b)
{
int temp = b;
b = a;
a = temp;
}
int main(void)
{
int a = 3;
int b = 2;
swap(a, b);
return 0;
}
上面的程序有什么问题吗?你会发现a和b的值根本就没有被交换。因为在main函数中调用swap函数时,只是将a、b的值3和2传递给了swap函数,swap函数中只是使用了这两个值而已,所以说自然不能交换main函数中的a、b值。
解决这个问题可以使用一个办法,即传递a、b的地址给swap函数。
void swap(int* a, int* b)
{
int temp = *b;
*b = *a;
*a = temp;
}
int main(void)
{
int a = 3;
int b = 2;
swap(&a, &b);
return 0;
}
传递指针并没有违反值传递这个规则,这里只是传递了a、b两个变量的地址给swap函数,swap函数可以使用这两个地址间接访问main函数中的a、b变量,自然而然可以交换它们的值。
2. 函数返回值问题
函数的返回值也是值传递的,但是需要注意的是:函数的返回值不能是其中栈上变量的地址,因为在函数调用完成后,函数中的栈上变量随之被销毁,你如果继续使用这个地址,将会导致非法访问。
char* get_message()
{
char msg[] = "Aren't pointers funs?";
return msg;
}
int main(void)
{
char* string = get_message();
puts(string);
return 0;
}
上面的程序有什么问题吗?上面的程序就是犯了返回栈上变量的地址问题,我们对这种问题称为野指针,因为它指向了非法区域。
3. 函数递归
所谓函数递归,就是一个函数可以直接或间接的调用自己。
int factorial(int n)
{
if (n == 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}
当然也可以用其它方法来实现这个函数。
int factorial(int n)
{
int j = 1;
int i = 1;
while (i <= n) {
j *= i;
i++;
}
return j;
}