🌹作者:小泽同学~
📝csdn个人主页:小泽同学~
📝码云:classmate-mzq
🤟motto:己所不欲,勿施于人and勿以善小而不为,勿以恶小而为之
————————————————
前言:不出意外的话,我将在这里记录我的大学编程学习。
因为我也是小白,所以如果大家看到问题的话,可以直接在下面评论或者加我v私我,感谢大家!
个人v:m0106gm(添加的话麻烦备注csdn)
祝我们前程似锦
本人使用的开发环境工具是vs
文章目录
1. 函数是什么2. 库函数3. 自定义函数4. 函数参数5. 函数调用6. 函数的嵌套调用和链式访问7. 函数的声明和定义写在最后1. 函数是什么
数学中我们常见到函数的概念,我们熟悉的数学中的函数f(x)=x2+2x+3,x值不同f(x)也就跟着变化,f(x,y)=2x+y也同理。而计算机也有函数,也能够进行这样的运算,但是你了解C语言中的函数吗?
维基百科中对函数的定义:子程序
在计算机科学中,子程序(即函数)是一个大型程序中的某部分代码, 由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
C语言中函数的分类:
库函数自定义函数
2. 库函数
为什么会有库函数?
我们知道在我们学习C语言编程的时候,总是在一个代码编写完成之后迫不及待的想知道结果,想
把这个结果打印到我们的屏幕上看看。这个时候我们会频繁的使用一个功能:将信息按照一定的格
式打印到屏幕上(printf)。在编程的过程中我们会频繁的做一些字符串的拷贝工作(strcpy)。在编程中我们也计算,总是会计算n的k次方这样的运算(pow)。
像上面我们描述的基础功能,它们不是业务性的代码。我们在开发的过程中每个程序员都可能用的到,为了支持可移植性和提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。
简单的总结,C语言常用的库函数都有:
IO函数 (即输入输出函数:printf,scanf ,getchar,putchar等)
字符串操作函数 (strlen,strcmp,strcpy等)
字符操作函数 (toupper,tolower等)
内存操作函数 (menset,mencpy等)
时间/日期函数 (time等)
数学函数 (sqrt,pow等)
其他库函数
下面我们来学习几个库函数学会函数的使用方法
strcpy:字符串拷贝函数 作用:将一个字符串的内容拷贝到另一个字符串里面函数原型:char * strcpy ( char * destination, const char * source )
【返回类型和参数均为指针类型,第一个参数是目标字符串,第二个字符串是源头字符串,即把第二个字符串的内容拷贝到第一个字符串里面去】所在头文件:srting.h
//代码1#include <stdio.h>#include <string.h>int main(){char arr1[20] = {0 }; char arr2[] = "i love you!";strcpy(arr1, arr2); //把arr2的内容拷贝到arr1中printf("%s", arr1); return 0;}
//代码2#include <stdio.h>#include <string.h>int main(){char arr1[] = "i love myself";char arr2[] = "i love you!";strcpy(arr1, arr2);printf("%s", arr1);return 0;}
代码2表明,字符串拷贝的时候,\0
也会被一同拷贝
使用strcpy的注意事项:目标字符串的大小一定要比源头字符串的大小大,否则会报错
pow:求幂函数 作用:求一个数字的N次方函数原型:double pow (double base, double exponent)
【返回类型和参数均为双精度浮点型,第一个参数是是底,第二个参数是幂】所在头文件:math.h
#include <stdio.h>#include <math.h>int main(){//因为2的10次方是整数,所以也可以用int型接受,不过会有警告int a = pow(2, 10); //求2的10次方 printf("%d", a);return 0;}
#include <stdio.h>#include <math.h>int main(){double a = pow(2, 10);printf("%lf", a);return 0;}
menset:内存设置函数 函数原型:void * memset ( void * ptr, int value, size_t num )
【返回类型为指针类型,第一个参数是指针类型,第二个参数是整型,第三个参数是无符号整型,即正整数】作用:将ptr所指向的内容的内存的前num个字节变成value所在头文件:string.h
#include <stdio.h>#include <string.h>int main(){char a[] = "mzq,i love you!"; memset(a, '*', 4); //把a中前4个字节的内存变成'*'printf("%s", a);return 0;}
使用库函数,必须包含 #include 对应的头文件。
3. 自定义函数
如果库函数能干所有的事情,那还要程序员干什么?
所有更加重要的是自定义函数。
自定义函数和库函数一样,有函数名,返回值类型和函数参数。
但是不一样的是这些都是我们自己来设计。这给程序员一个很大的发挥空间。
函数的组成:ret_type fun_name(para1, * ){statement;//语句项}ret_type 返回类型fun_name 函数名para1 函数
写一个函数求两个数的最大值
#include <stdio.h>//求最大值,是一个整数,所以返回类型为int型,get_max为函数名,有俩个参数int get_max(int x, int y){int max = 0;if (x > y){max = x;}else{max = y;}return max;}int main(){int a = 0, b = 0;scanf("%d %d", &a, &b);int max = get_max(a, b);printf("%d更大", max);return 0;}
//求最大值的函数也可以这么写:int get_max(int x, int y){return x > y ? x : y;}//三目运算符,如果x>y,表达式结果为x,否则为y
写一个函数,作用是对两个数进行交换
看看下面的代码,你觉得可以吗?
#include <stdio.h>//只是交换俩个数值,不需要返回,故返回类型为voidvoid swap(int x, int y){int z = x; //创建第三变量用来临时存放x的值x = y;y = z;}int main(){int a = 0, b = 0;scanf("%d %d", &a, &b);printf("变换前:a=%d,b=%d\n", a, b);swap(a, b);printf("变换后:a=%d,b=%d\n", a, b);return 0;}
看看结果吧:
可以看到,没有改变!
因为无论是a,b还是x,y都是局部变量,作用域都只在它们对应的
{}
即对应的函数中,生命周期自函数结束就停止了,所以其实并没有改变俩个数真正写出交换两个数的函数看下面函数调用中的传址调用
4. 函数参数
实际参数(实参): 真实传给函数的参数,叫实参。实参可以是:常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。 形式参数(形参): 形式参数是指函数调用时括号中的变量因为形式参数只有在函数被调用的过程中才实例化(分配内存单元)所以叫形式参数。形参实例化后相当于实参的一份临时拷贝,修改形参不会改变实参形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
上面get_max函数和swap函数中的参数 x,y就是形式参数。在main函数中传给 swap 和get_max的a,b则是实际参数
看看这句话:实参可以是:常量、变量、表达式、函数等
前面的函数我们实参只用了变量,实际是常量,表达式,甚至是函数都可以作为实参,但是它的结果一定是一个确定的值
看看代码:
#include <stdio.h>int get_max(int x, int y){return x > y ? x : y;}int main(){int max = get_max(14, 5+3); //可以是常数,可以是表达式printf("%d更大\n", max);max = get_max(235, get_max(35+235, 53));//可以是函数printf("%d更大\n", max);return 0;}
5. 函数调用
传值调用
传值调用时,形参是实参的一份临时拷贝;函数的形参和实参分别占用不同内存块,对形参的修改不会影响实参;形参和实参使用的不是同一个内存地址;
传址调用
传址调用时可通过形参操作实参;传址调用是把函数外部创建的变量的内存地址传递给函数参数的一种调用函数的方式;使函数内部可以直接操作函数外部的变量(让函数内外的变量建立起真正的联系);
上面的函数我们都是传值调用,那传址调用怎么用呢?
还记得上面我们讲到的交换俩个变量的值的函数swap吗?要实现这个函数,我们就需要传址
#include <stdio.h>void swap(int* p1, int* p2)//实参与形参的类型应该一样。所以形参是指针{int t = *p1; //'*'是解引用,获取指针所指向的数字*p1 = *p2;*p2 = t;}int main(){int a = 0, b = 0;scanf("%d %d", &a, &b);printf("变换前:a=%d,b=%d\n", a, b);swap(&a, &b); //'&'是取址符,实参是地址,把变量a和b的地址传给函数printf("变换后:a=%d,b=%d\n", a, b);return 0;}
也就是,如果我们要改变实参的值,就需要传址,如果不需要改变实参的值,则只需要传值就可以
写一个函数,实现一个整形有序数组的二分查找。
#include <stdio.h>void search(int arr[],int a,int sz){int left = 0;int right = sz-1;while (left <= right){int mid = (left + right) / 2;if (arr[mid] > a){right = mid - 1;}else if(arr[mid]<a){left = mid + 1;}else{printf("找到了,下标为%d\n", mid);break;}}if (left > right){printf("找不到");}}int main(){int arr[] = {12,35,64,546,584,3524,54643,2425236};int a = 0;scanf("%d", &a);int sz = sizeof(arr) / sizeof(arr[0]);search(arr,a,sz);return 0;}
写一个函数,每调用一次这个函数,就会将 num 的值加5。
#include <stdio.h>void add(int num){num+=5;}int main(){int num = 10;add(num);printf("%d\n", num);add(num);printf("%d\n", num);add(num);printf("%d\n", num);return 0;}
没有改变!!!为什么?因为我们此时需要改变实参,所以我们需要传址
#include <stdio.h>void add(int *num){*num+=5;}int main(){int num = 10;add(&num);printf("%d\n", num);add(&num);printf("%d\n", num);add(&num);printf("%d\n", num);return 0;}
6. 函数的嵌套调用和链式访问
1.函数的嵌套调用>
//main函数调用了test1,test1调用了test2,test2又调用了test3//这就是函数的嵌套调用#include <stdio.h>void test3(){printf("hihi");}void test2(){test3();}void test1(){test2(); }int main(){test1(); return 0;}
#include <stdio.h>void line(){printf("hehe\n");}void three_line(){int i = 0;for(i=0; i<3; i++){line();}}int main(){three_line();return 0; }
2.函数的链式访问>
即一个函数的返回值作为另一个函数的参数来使用
#include <stdio.h>int get_max(int x, int y){return x > y ? x : y;}int main(){//get_max函数的返回值作为printf函数的参数printf("%d\n", get_max(23, 32));//get_max函数的返回值作为get_max函数的参数max = get_max(235, get_max(35+235, 53));printf("%d更大\n", max); return 0;}
7. 函数的声明和定义
先来看看下面:写一个两个数相加的函数代码
#include <stdio.h>int main(){int a = 0, b = 0;scanf("%d %d", &a, &b);printf("%d", add(a, b));return 0;}int add(int x, int y){int z = x + y;return z;}
可以运行吗?
可以看到,可以运行,但是显示器一片空白,没有产生结果,同时编译器给了我们警告
为什么?
因为程序执行的方向是从上到下的,当进行main函数遇到add的时候,计算机之前并没有见过它,所以给出了警告!
那应该怎么办呢?应该这样:
#include <stdio.h>int add(int x, int y); //在add使用前进行声明,这就是函数的声明,返回类型+函数名+参数+分号int main(){int a = 0, b = 0;scanf("%d %d", &a, &b);printf("%d", add(a, b));return 0;}int add(int x, int y) //这是函数的定义{int z = x + y;return z;}
函数声明:
告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数
声明决定不了。函数的声明一般出现在函数的使用之前。要满足先声明后使用。函数的声明一般要放在头文件中的。
函数声明时也可以不写参数名,只写参数类型即可,比上面的add函数声明可以这样写
int add(int ,int);
函数定义:
函数的定义是指函数的具体实现,交待函数的功能实现
写在最后
非常感谢你耐着性子把它读完
如果觉得我写的还不错,希望能点个赞或评论一下为我加油,感谢✌
愿我们一起努力奔跑,向美好的未来不断前进,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!