C语言初阶秘籍3
Hello,大家好!!!这���是小周为您带来的呕心沥血之作------C语言秘籍!!
C语言秘籍分为初阶和高阶两部!!跟着小周学定会让你C语言功力大成,称霸武林,话不多说,马上开讲!!!!!
三、函数
1、函数是什么?
数学中我们常见到函数的概念。但是你了解C语言中的函数吗?
维基百科中对函数的定义:子程序
在计算机科学中,子程序(英语:Subroutine, procedure, function, routine, method, subprogram, callable unit),是一个大型程序中的某部分代码, 由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代 码,具备相对的独立性。
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
2、C语言中函数的分类
-
库函数
-
自定义函数
2.1 库函数
为什么会有库函数?
-
我们知道在我们学习C语言编程的时候,总是在一个代码编写完成之后迫不及待的想知道结果,想把这个结果打印到我们的屏幕上看看。这个时候我们会频繁的使用一个功能:将信息按照一定的格式打印到屏幕上(printf)。
-
在编程的过程中我们会频繁的做一些字符串的拷贝工作(strcpy)。
-
在编程是我们也计算,总是会计算n的k次方这样的运算(pow)。
像上面我们描述的基础功能,它们不是业务性的代码。我们在开发的过程中每个程序员都可能用的到,为了支持可移植性和提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。
理解:C语言中把常用的功能进行了封装,封装成一个一个的函数,提供出来供大家使用,C语言并不去直接实现库函数,而是提供了C语言的标准和库函数的约定,库函数的实现一般是由编译器去实现的
比如 scanf C语言规定了它的功能,名字,参数,返回值
那怎么学习库函数呢?
这里给大家推荐一个网站也是经常出现在之前的讲解中的一个网站
[cplusplus.com - The C++ Resources Network](https://legacy.cplusplus.com/)
简单的总结,C语言常用的库函数都有:
-
IO函数 输入输出函数 scanf printf putchar getchar
-
字符串操作函数 strlen strcmp
-
字符操作函数 islower isupper
-
内存操作函数 memset memcmp
-
时间/日期函数 time
-
数学函数 sqrt pow
-
其他库函数
我们参照文档,学习几个库函数:
strcpy
char * strcpy ( char * destination, const char * source );
memset
void * memset ( void * ptr, int value, size_t num );
首先我们打开网站
在上方的搜索框中搜索我们要学习的库函数strcpy,然后点击go
在这里大家可以看到库函数的各项信息
首先是我们看这个绿色的小字,图片中已经标注
其次就是这个函数功能的英文介绍
如果说屏幕前的你真的英语看不懂也可以选中之后右键翻译,这个函数的功能是
将源头指向的 C 字符串复制到目标指向的数组中,包括终止 null 字符(并在该点停止)。
英文字体中的斜体字与函数参数是对应的
其次是对函数参数的具体解释
source---是被复制的字符串,destination---是被覆盖的字符串
这个是返回值,告诉我们这个函数返回destination的首地址
然后有列举的例子和输出的样例
红色框框我们点击可以直接跳转运行
在这里可以运行看看,同时我们可以看到其他类似的库函数
我们对strcpy初步的学习就基本完事了,然后我们代码详细说一下
函数的返回值如果我们需要它我们就用对应的类型接收,如果实际情况不需要的话,可以不接受函数返回值
#include #include //库函数的使用要调用头文件 int main() { char arr1[] = "good good study";//源头 char arr2[20] = "xxxxxxxxxxxxxxxxxxx";//目的地 //对于数组,数组名其实是数组第一个元素的地址,也就是起始地址 strcpy(arr2, arr1); printf("%s\n", arr2); return 0; }
我们调试来看一看这个\0到底是否复制过来了
我们发现确确实实复制过来了,那到这里是不是对strcpy库函数的学习有了自己的认识呢?
好的我们接着来看memset
首先来看memset的返回类型,以及函数参数,函数的功能是将 ptr 指向的内存块的第一个字节数设置为指定值
这里有英文的介绍,话不多说代码演示
通俗易懂来说就是把数组arr的地址传进去,然后,从首地址开始,将num个位置的值全部更改为x
2.2 自定义函数
那我们说所有如果库函数能干所有的事情,那还要程序员干什么?所以更加重要的是自定义函数。
自定义函数和库函数一样,有函数名,返回值类型和函数参数。
但是不一样的是这些都是我们自己来设计。这给程序员一个很大的发挥空间。
函数的组成:
ret_type fun_name(para1, *) { statement;//语句项 } ret_type 返回类型 fun_name 函数名 para1 函数参数
一整个{ }是函数体
我们举一个例子:
写一个函数可以找出两个整数中的最大值
int get_max(int x , int y) { int z = (x > y ? x : y); return z; } int main() { int num1 = 0; int num2 = 0; scanf("%d %d", &num1 ,&num2); //正常计算 int max1 = (num1 > num2 ? num1 : num2); //用函数来得到最大值 int max2 = get_max(num1, num2); //输出最大值 printf("max = %d\n", max1); printf("max = %d\n", max2); return 0; }
3、函数的参数
好,我们接着往下看,再举个例子
写一个函数可以交换两个整形变量的内容
void Swap1(int x, int y) { int tmp = 0; tmp = x; x = y; y = tmp; } int main() { int num1 = 1; int num2 = 2; Swap1(num1, num2); printf("Swap1::num1 = %d num2 = %d\n", num1, num2); return 0; }
我们来运行看看
哎?我们发现怎么没有实现交换的功能呢?这不是出现问题了吗?这就要提到接下来讲的两个不同的东西
我们先来调试看看
上述的代码在内存中是这样表示的
3.1 实际参数(实参)
真实传给函数的参数,叫实参。
实参可以是:常量、变量、表达式、函数等。
int get_max(int x, int y) { int z = (x > y ? x : y); return z; } int main() { int a = 0; int b = 0; //输入 scanf("%d %d", &a, &b);//3 5 //使用函数来完成 int m = get_max(a, b);//变量 m = get_max(a, 7);//变量,常量 m = get_max(a, 2+3);//表达式 m = get_max(a, get_max(4, 8));//函数的参数是函数调用 //输出 printf("较大值是:%d\n", m); return 0; }
大家可以自己下去运行,看看是否能成功运行
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
3.2 形式参数(形参)
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内
存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数
中有效。
实际参数 - 实参 当实参传递给形参的时候,形参是实参的一份临时拷贝,所以对形参的修改不会影响实参
//形式参数 - 形参 void Swap(int* pa, int* pb) { int tmp = *pa;//tmp = a *pa = *pb;//a = b *pb = tmp;//b = tmp } int main() { int a = 0; int 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; }
这回我们发现我们成功实现了两个数的互换
上述的代码在内存中是这样表示的
这里可以看到 Swap1 函数在调用的时候,x ,y 拥有自己的空间,同时拥有了和实参一模一样的内容。
所以我们可以简单的认为:形参实例化之后其实相当于实参的一份临时拷贝
4、函数的调用
4.1 传值调用
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。在这种设计中,形参是实参的一份临时拷贝,对形参的修改不会影响实参
4.2 传址调用
通过形参的指针就能够访问到函数外部的变量,并进行操作
-
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
-
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操
作函数外部的变量。
void Swap1(int x, int y)//传值调用 { int tmp = 0; tmp = x; x = y; y = tmp; } void Swap2(int* pa, int* pb)//传址调用 { int tmp = *pa;//tmp = a *pa = *pb;//a = b *pb = tmp;//b = tmp } int main() { int num1 = 0; int num2 = 0; scanf("%d %d", &num1, &num2); printf("交换前:num1 = %d num2 = %d\n", num1, num2); Swap1(num1, num2); printf("交换后:num1 = %d num2 = %d\n", num1, num2); return 0; }
4.3 练习
在这里找了几个很常见的习题给大家一点时间自己动手做做,相信你一定可以
练习1:写一个函数可以判断一个数是不是素数
#include int is_prime(int n) { int j = 0; for (j = 2; j
-