“少年回头望 笑我还不快跟上。”
目录
1.什么是函数
一个程序可能会用到很多次,如果每次都写这样一段重复的代码,不但费时费力、容易出错,而且交给别人时也很麻烦,所以C语言提供了一个功能,允许我们将常用的代码以固定的格式封装成一个独立的模块,只要知道这个模块的名字就可以重复使用它,这个模块就叫做函数(Function)。函数相较于其他代码,具备相对的独立性。
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常会被集成为软件库。
2.库函数
C语言中函数分类:
1.库函数
2.自定义函数
为什么会有库函数?
在我们学习C语言编程的时候,有一些像scanf,printf,strcpy,strlen等基础功能,它们不是业务性代码,在开发的过程中每个程序员都会用得到,为了支持可移植性和提高程序的效率,所以C语言基础库提供了一系列类似的库函数,方便程序员进行软件开发。
注:使用库函数,必须#include相应的头文件。
举个栗子:
1.
int main()
{
char arr1[] = "#####################";
char arr2[] = "hello world";
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
2.
int main()
{
char arr2[] = "hello world";
memset(arr2, 'x', 5);
printf("%s\n", arr2);
return 0;
}
注:memset是以字节数为单位进行初始化的。
3.自定义函数
除了库函数,我们还可以编写自己的函数,拓展程序的功能。自己编写的函数称为自定义函数。自定义函数和库函数在编写和使用方式上完全相同,只是由不同的机构来编写。
ret_type fun_name ( para1 )
{ statement;//语句项 }
ret_type 返回类型 fun_name 函数名 para1 函数参数
举个栗子:
int Max(int a, int b)
{
return (a > b ? a : b);
}
int main()
{
int a = 0;
int b = 0;
scanf("%d%d", &a, &b);
int max=Max(a, b);
printf("%d", max);
return 0;
}
void Change(int *a, int *b)
{
int tmp = 0;
tmp = *a;
*a =*b;
*b = tmp;
}
int main()
{
int a = 0;
int b = 90;
printf("a:%db:%d\n", a, b);
Change(&a,&b);
printf("a:%db:%d\n", a, b);
return 0;
}
4.函数的参数
实参:
真实传给函数的参数。可以是:常量,变量,表达式,函数等。在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
形参:
在定义函数时,函数名后括号中的变量,因为形式参数只有在调用的时候才实例化(分配空间),所以叫形式参数。形参当函数调用完之后就会被销毁,因此形参只在函数中有效。
5.函数的调用
传值调用:
函数的形参和实参分别占有不同的内存块,对形参改变不会影响实参。形参实例化之后其实相当于实参的一份临时拷贝。
传址调用:
传址调用是把函数外部创建的变量的内存地址传递给函数参数的一种调用方式。
这种传参方式可以让函数和函数外部的变量建立起真正的联系。也就是函数内部可以直接操作函数外部的变量。
6.练习
1. 写一个函数可以判断一个数是不是素数。
int is_prime(int i)
{
for (int j = 2; j <= sqrt(i); j++)
{
if (i%j == 0)
{
return 0;
}
}
return 1;
}
int main()
{
for (int i = 100; i <= 200; i++)
{
if (is_prime(i))
{
printf("%d ", i);
}
}
return 0;
}
2. 写一个函数判断一年是不是闰年。
int is_leap_year(int y)
{
return((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0));
}
int main()
{
int y = 0;
int i = 0;
scanf("%d", &y);
if (is_leap_year(y))
{
printf("是闰年");
}else
printf("不是闰年");
return 0;
}
3. 写一个函数,实现一个整形有序数组的二分查找。
int binary_search(int k,int arr[], int sz)
{
int left = 0;
int right = sz - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (arr[mid] < k)
{
left = mid + 1;
}
else if (arr[mid]>k)
{
right = mid - 1;
}
else if (arr[mid] == k)
{
return mid;
}
}
return -1;
}
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int k = 7;
int sz = sizeof(arr) / sizeof(arr[0]);
int tmp=binary_search(k,arr, sz);
if (tmp == -1)
{
printf("找不到");
}
else
{
printf("找到了,下标为%d\n", tmp);
}
return 0;
}
4. 写一个函数,每调用一次这个函数,就会将num的值增加1。
int Count(int* pnum)
{
(*pnum)++;
}
int main()
{
int num = 0;
Count(&num);
Count(&num);
Count(&num);
Count(&num);
printf("%d", num);
return 0;
}
7.函数的嵌套调用和链式访问
嵌套调用
void Print()
{
printf("hello world\n1");
}
void test()
{
Print();
}
int main()
{
test();
return 0;
}
函数可以嵌套调用不可以嵌套定义。
//错误示范
void Print()
{
printf("hello world\n1");
}
int main()
{
void test()
{
Print();
}
return 0;
}
链式访问
链式访问是把一个函数的返回值作为另外一个函数的参数。
#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
//结果是啥?
return 0;
}
解析: 1.先执行 printf("%d", 43),其返回值为2
2. 再执行printf("%d",2),其返回值为1
3.再执行printf("%d",1)