函数具备相对的独立性,有输入、输出、返回值,提供对过程的封装和细节的隐藏
C语言中函数的分类
·库函数(完成有限的功能)
·自定义函数(可以实现自己想要的逻辑)
一、库函数
C语言中常用的库函数
·IO函数(printf、scanf、getchar())
int printf(const char* format,...);
·字符串操作函数(strcpy、strcmp、strstr)
char* strcpy(char* destination,const char* source);
·内存操作函数
·时间/日期函数
·数学函数
·其他库函数
注意:使用库函数必须包含相对应的#include头文件
二、自定函数
有函数名、返回值类型、函数参数
例:写一个函数找出两个数中的最大值
int get_max(int x, int y)
{
return (x > y) ? (x): (y);
}
int main()
{
int num1 = 19;
int num2 = 3;
int max = get_max(num1, num2);
printf("%d\n", max);
return 0;
}
三、函数的参数
实参(实际参数):真实传给函数的参数
形参(形式参数):函数参数部分的参数只有在函数被调用的过程中才实例化(分配单元)
形式参数当函数调用完成之后就自动销毁了(形式参数只在函数内部才有效)
形参实例化之后其实相当于实参的一份临时拷贝
函数设计的注意事项:
(1)参数不要过多
(2)代码的可复用性
(3)函数参数和返回值的设计要满足功能的要求
四、函数的调用
传值调用:函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参
传址调用:函数的形参和实参占用不同的空间,但是形参中存放了实参的地址
练习:
1、写一个函数可以判断一个数是不是素数
#include<stdio.h>
#include<math.h>
int is_prime(int n)
{
int i = 0;
for (i = 2; i <= sqrt(n); i++)
{
if (n%i == 0)
return 0;
}
return 1;
}
int main()
{
int n = 13;
int ret = is_prime(n);
if (ret == 1)
printf("是素数\n");
else
printf("不是素数\n");
system("pause");
return 0;
}
2、写一个函数判断一年是不是润年
#include<stdio.h>
int is_year(int year)
{
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
return 1;
return 0;
}
int main()
{
int year = 2011;
int ret = is_year(year);
if (ret == 1)
printf("是润年\n");
printf("不是润年\n");
system("pause");
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/adb79310af1f28b4ac5df3c235febe27.png)
3、写一个函数,实现一个整型有序数组的二分查找
#include<stdio.h>
int bin_search(int* arr, int left, int right,int key)
{
int mid = 0;
while (left <= right)
{
mid = (left + right) >> 1;
if (arr[mid] < key)
{
left = mid + 1;
}
else if (arr[mid] > key)
{
right = mid - 1;
}
else
{
return 1;
}
}
return -1;
}
int main()
{
int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int sz = sizeof(arr) / sizeof(arr[0]);
int ret = bin_search(arr, 0, sz, 6);
if (ret == 1)
printf("找到了\n");
else
printf("没有找到\n");
system("pause");
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/b3d1171762e8a32dc019d084319e1992.png)
4、写一个函数,只要调用一次就可以将参数的值增加1
五、函数的嵌套调用和链式访问
1、嵌套调用:在一个函数内部调用另一个函数
void print()
{
printf("hello world!\n");
}
void test()
{
print();
print();
}
2、链式访问:一个函数的返回值作另一个函数的参数
int ret = strlen(strcat("hello", "bit"));
printf("%d\n", ret);
六、函数的声明和定义
1、函数的声明
(1)必须有函数名、参数、返回类型
(2)先声明后使用
(3)函数的声明一般放在头文件中
2、函数的定义:函数的具体实现,交到函数的功能实现
ADD.h的内容
#ifndef __ADD_H__
#define __ADD_H__
//函数的声明
int ADD(int x, int y);
#endif
ADD.c的内容
#include "ADD.h"
int ADD(int x,int y)
{
return x + y;
}
防止头文件多次引用
七、链接属性
1、外部链接属性:一个标识符,不仅可以在当前源文件使用,使用extern的声明可以在其他源文件使用
add.c源文件
int Add(int x, int y)//具有外部链接属性的函数
{
return x + y;
}
int g_val = 2018;//具有外部链接属性的变量
test.c源文件
#include<stdio.h>
extern int Add(int, int);
extern int g_val;
int main()
{
int a = 1;
int b = 2;
int ret = Add(a,b);
printf("g_val = %d\n",g_val);
return 0;
}
2、内部链接属性:具有内部链接属性的变量,只能在当前源文件中使用
具有外部链接属性的标识符加上static关键字就变成了内部链接属性
add.c源文件
static int Add(int x, int y)//具有内部链接属性的函数
{
return x + y;
}
static int g_val = 2018;//具有内部链接属性的变量
test.c源文件
#include<stdio.h>
extern int Add(int, int);
extern int g_val;
int main()
{
int a = 1;
int b = 2;
int ret = Add(a,b);
printf("g_val = %d\n",g_val);
return 0;
}
3、无属性:局部变量是无属性的
·