目录
1.函数是什么?
数学中我们经常见到函数概念,但是你了解C语言中的函数吗?维基百科中对函数的定义:子程序
- 在计算机科学中,子程序是一个大型程序中的某部分代码,由一个或多个语句块组成,他负责完成某项特定任务,而且相较于其他代码,具备相对的独立性
- 一般会有输入参数病有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库
C语言中函数的分类:1.库函数 2.自定义函数
2.库函数
为什么会有库函数?
1.我们知道在我们学习C语言的编程的时候,总是在一个代码编写完成之后迫不及待的想知道结果,想把这个结果打印到我们屏幕上看看。这个时候我们会频繁使用一个功能:将信息按照一定的格式打印到屏幕上(printf)
2.在编程过程中我们会频繁的做一些字符串拷贝工作(strcpy)
3.在编程是我们叶计算,总是会计算n的k次方这样的运算(pow)
像上面我们描述的基础功能,他不是业务性的代码,我们在开发的过程中每个程序员都可能用得到,为了支持可移植性和提高程序的效率,所有C语言的基础库中提供了一系列类似的库函数,方便进行程序员进行软件开发
简单的总结,C语言中常用的库函数都有:
- IO函数
- 字符串操作函数
- 字符操作函数
- 内存操作函数
- 时间/日期函数
- 数学函数
- 其他库函数
举例:
strcpy--string copy——字符串拷贝
strlen---string length——字符串长度有关
strcpy
char *strcpy(char *destination,const chat *source);
int main()
{
char arr1[]="bit";
char arr2[]="#######";
// bit\0###";
strcpy(arr2,arr1);//把arr1拷贝到arr2之中去
printf("%s\n",arr2);
//strcpy--string copy——字符串拷贝
//strlen---string length——字符串长度有关
return 0;
}
strcpy函数在拷贝过程中将arr1中的\0也拷贝到arr2之中。可以运行代码过程中用监视窗口观察arr2中的数据变化
memset
void *memset(void *ptr,int value,size_t num);
通俗来讲就是指向一块地址,将地址的num个字节设置成value的值
//memset
//memset__内存 set————设置
int main()
{
char arr[]="hello world";
memset(arr,'*',5);
printf("%s\n",arr);
//***** world
return 0;
}
3.自定义函数
自定义函数和库函数一样,有函数名,有返回值类型和函数参数
函数的组成:
ret_type fun_name(paral,*)
{
statement;//语句项
}
ret_type 返回类型
fun_name 函数名
paral 函数参数
举个例子:找出两个数之间的较大值
//定义函数
get_max(int x,int y)
{
if(x>y)
return x;
else
return y;
}
int main()
{
int a=10;
int b=20;
//函数的使用
int max=get_max(a,b);
printf("max=%d\n",max);
return 0;
}
写一个函数交换两个整型变量的内容
void Swap(int x;inty)
{
int tmp=0;
tmp=*pa;
*pa=*pb;
*pb=tmp;
}
int main()
{
int a=10;
int b=20;
//int *pa=&a;//pa指针变量
//*pa=20;//解引用操作
Swap(&a,&b);
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
4.函数参数
实际参数(实参):
真实传给函数的参数,叫实参。实参可以说:常量,变量,表达式,函数。无论实参是何种类型的量,在进行函数调用时,他们都必须有确定的值,以便把这些值传给形参
形式参数(形参):
形式参数是指函数名后括号中变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数,形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效
形参实例化之后其实相当于实参的一份临时拷贝
5.函数调用
传值调用:
函数的形参和实参分别占有不同的内存块,对形参的修改不影响实参
传址调用
- 传址调用是把函数外部创建的变量的内存地址传递给函数参数的一种调用函数的方式
- 这种传参当时可以让函数和函数外边的变量建立起真正的练习,也就是函数内部可以直接操作函数外部的变量
练习:
1.写一个函数可以判断一个数是不是素数
//是素数返回1,不是素数返回1
int is_prime(int n)
{
//2到n减1的数依次试除
int j=0;
for(j=2;j<n;j++)
//for(j=2;j<=sqrt(n);j++)
{
if(n%j==0)
return 0;
}
return 1;
}
int main()
{
//打印100-299之间的素数
int i=0;
for(i=100;i<=200;i++)
{
//判断i是否为素数
if(is_prime(i)==1)
printf("%d ",i);
}
return 0;
}
2.写一个函数判断一年是不是闰年
int is_leap_year(int y)
{
if(y%4==0&&y%100!==0||(y%400==0))
return 1;
else
return 0;
}
int main()
{
int year=0;
for(year=1000;year<=2000;year++)
{
//判断year是否为闰年
if(is_leap_year(year)==1)
{
printf("%d ",year);
}
}
return 0;
}
3.写一个函数,实现一个整型有序数组的二分查找
// 传递过去数组arr的首元素地址,本质上应该是个指针
int binary_search(int arr[],int k,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
{
return mid;
}
}
return -1;
}
int main()
{
//二分查找
//在一个有序数组中查找具体的某个数
//如果找到了返回这个数的下标,找不到返回-1
int arr[]={}
int k=7;
int sz=sizeof(arr)/sizeof(arr[0]);//计算数组元素个数,以便确定右下标的值
int ret=binary_search(arr,k)
if(ret==-1)
{
printf("找不到指定的数字\n");
}
else
{
printf("找到了,下标是:%d",ret);
}
return0;
}
4.写一个函数,每调用一次这个函数,就会将num的值增加1
void Add(int *p)
{
(*p)++;
}
int main()
{
int num=0;
Add(&num);
printf("num=%d\n",num);//1
Add(&num);
printf("num=%d\n",num);//2
Add(&num);
printf("num=%d\n",num);//3
return 0;
}
6.函数的嵌套调用和链式访问
函数和函数是有机会组合在一起的
嵌套调用
链式访问:把一个函数的返回值作为另外一个函数的参数
7.函数的声明和定义
函数声明:
1.告诉编译器由一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在无关紧要。
2.函数的声明一般出现在函数使用之前。要满足先声明后使用
3.函数的生命一般要放在头文件中
函数定义:
函数的定义是指函数的具体实现,交待函数的功能实现