首先,祝大家新年快乐!
声明:因本人为非科班转码,个人水平有限,博客中难免有不准确之处,如有读者发现,本人恳请大家积极指出,本人也想知道自己的错误在哪里。欢迎大家一起指正,共同进步。
目录
1.函数是什么(从数学函数到编程函数)
2.函数的分类
2.1 传值函数
2.1.1 例子
④特殊的非void的传值函数
2.1.2?知识点
2.2 传址函数
2.2.1 例子
2.2.2 知识点
2.3 传值函数 VS 传址函数
2.4 另一种分类(库函数和自定义函数)
3.函数的声明、定义与调用
3.1 函数的声明、定义
3.2 形参与实参
3.3 函数调用
4.函数的嵌套与链式访问
4.1 函数的嵌套
4.2 函数的链式访问
1.函数是什么(从数学函数到编程函数)
在数学中,我们经常说y=f(x),f(x)就是函数。实际上,这里的x与y也是有限制关系的。在数学中,我们对应自变量中的所有x,都有唯一与之对应的y与其对应,我们把y与x之间的关系称为函数。简言之,函数就是因变量与自变量对应的关系。
那么,到了编程中,函数又是什么呢?
这里,不得不谈谈为什么c语言中会出现函数了。在c语言中,我们刚开始都是在int main{}里面编写代码的,但是我们想一下,如果我们要实现很多功能,而这些功能可能不止需要实现一次,那我们写的代码会是什么样子??会特别冗长,对吧?编程中,为了避免类似的重复造轮子的现象,函数应运而生。
函数,由一个或者几个语句块组成,可以实现一些特定功能,并且彼此之间相互独立。
2.函数的分类
函数分为两种,传值函数(传空值我也算进这里)和传址函数。
2.1 传值函数
2.1.1 例子
①打印函数(实现打印两句话的功能)
#include <stdio.h>
void print()
{
printf("新年快乐\n");
printf("三连支持\n");
}
int main()
{
print();
return 0;
}
?②乘法函数(计算两个数的乘积)
#include <stdio.h>
int mul(int x, int y)//乘法函数
{
return (x * y);
}
int main()
{
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
int z = mul(x, y);
printf("%d", z);
return 0;
}
③获取字符串长度(获取已知的字符串长度)
#include <stdio.h>
int get_length(char *pa)
{
if (*pa == '\0')
{
return 0;
}
else
{
return 1 + get_length(++pa);//pa++是错误的
}
}
int main()
{
char arr[] = "hello world";
int length = get_length(arr);
printf("%d", length);
return 0;
}
④特殊的非void的传值函数
eg:
int print(int x)
{
? return ;//return后面没有任何东西,但是return这一句会运行到。
}
2.1.2?知识点
经编译器佐证,传值函数正如其名字所说,就是把实际参数传过去,但是传的只是值,且该值是实际参数的一个副本,传值函数导致的值变化并不影响其实际参数的值。
传值函数分为有返回类型的(int, float, char等)和无返回类型的。传值函数中,return(返回值)的类型、主要是定义保存返回值的变量类型,函数返回值定义类型三者必须保持一致。
2.2 传址函数
2.2.1 例子
#include <stdio.h>
void swap (int *pa, int *pb)//交换函数值
{
int temp = 0;
temp = *pa;
*pa = *pb;
*pb = temp;
}
int main()
{
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
printf("%d %d\n", x, y);
swap (&x, &y);
printf("%d %d\n", x, y);
}
2.2.2 知识点
传址函数,顾名思义,就是实参传递的为地址。在函数调用后,可以通过函数内的变量改变函数外的变量,即实参。(方法是:通过指针变量解引用修改实参)。如2.2.1的例子中,程序为输入两个数,再输出。通过函数交换两个变量的值,再一次输出。例子中的函数为传址函数,功能是改变指针所对应的值。既然是传址函数,就是对实参进行调整,自然不需要返回值,也就是传址函数基本为void类型。
2.3 传值函数 VS 传址函数
传值函数和传址函数,传值函数是开辟了新的内存单元对实参进行了一份复制,因此传值函数不影响实参。同时,传值函数一般会返回一个值。而传址函数传递的是地址,并没有开辟新的内存单元,而是在原有的内存单元下进行调整。所以,传址函数会影响实参(解引用)。
关于传址与传值,该用哪个在于:如果我们想要得到的结果为一个,基本为传值函数。(这并不意味着传值函数只能返回一个值,比如返回数组、结构体);如果我们想要的结果为2个及以上,多为传址函数。另外,需要对实参进行修改,为传址;不需要对实参进行修改,为传值。
2.4 另一种分类(库函数和自定义函数)
库函数,就是编程语言给定的函数,这种函数存在的理由为这种函数功能引用频繁。在引用库函数的过程中,我们需要加上头文件,并结合相关文档进行调用,引用例子:# include <xxxxx.h.>。对于库函数,我们不需要每个都记忆,只需要能看懂相关文档,理解相关函数如何调用以及函数功能是什么即可,工具如MSDN。
?
而自定义函数,就是用户自己定义的函数,需要符合函数规范。(声明、定义、调用)我们编程经常写的为自定义函数。
3.函数的声明、定义与调用
3.1 函数的声明、定义
根据C语言语法规范,函数的声明必须在函数调用之前。函数声明只需要给出函数大致框架即可,不需要特别确定。其中,函数声明需要确定的有:返回类型、函数名称、形参类型。
函数的定义则需要把函数具体实现凸显出来。
3.2 形参与实参
形参(我叫它形式上的参数):指函数名称括号内的变量。因为这些变量只有在函数调用后才会被实例化,才会被实例化,所以称为形参。
根据定义,形参只能是变量。
实参:函数调用时的括号内的那些东西。
实参可以是变量,可以是常量,可以是表达式,也可以是函数。
以如下代码为例:
#include <stdio.h>
int mul(int x, int y)//乘法函数
{
return (x * y);
}
int main()
{
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
int z = mul(x, y);
printf("%d", z);
return 0;
}
eg:
①变量
int z = mul (x, y0;
②常量
int z = mul (2, 3);
③表达式
int z = mul (2+1, 3-2);
④函数
int z = mul (mul (2, 3), mul (10, 10) );
3.3 函数调用
函数调用只需要确定调用函数以及实参即可。3.2中的四种情况均为函数调用的例子,需要与函数声明中的形参定义类型一致,如要存放最终的返回值,还需要定义一致的变量类型。
这里,我们主要看一下函数声明、定义、调用的两种形式。
①声明和定义放一起
#include <stdio.h>
void swap (int *pa, int *pb)//交换函数值
{
int temp = 0;
temp = *pa;
*pa = *pb;
*pb = temp;
}
int main()
{
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
printf("%d %d\n", x, y);
swap (&x, &y);
printf("%d %d\n", x, y);
}
②先声明,再引用,最后定义
#include <stdio.h>
void swap (int *pa, int *pb);//交换函数值
int main()
{
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
printf("%d %d\n", x, y);
swap (&x, &y);
printf("%d %d\n", x, y);
}
void swap (int *pa, int *pb)//交换函数值
{
int temp = 0;
temp = *pa;
*pa = *pb;
*pb = temp;
}
在实际的代码编辑中,我们推荐第一种方案。然而,在实际工作中,我们需要将函数声明定义在同一个头文件(.h)文件中,函数定义放在(.c)文件中。具体原因不做说明,感兴趣的可以自行查阅。
4.函数的嵌套与链式访问
4.1 函数的嵌套
#include <stdio.h>
void star1 ()
{
printf("*\n");
}
void star2 ()
{
printf("**\n");
}
void star3 ()
{
printf("***\n");
}
void star()
{
printf("打印小星星\n");
star1();
star2();
star3();
}
int main()
{
star();
return 0;
}
在上列代码中,main函数调用了star函数,而star函数又分别调用了star1、star2、star3函数。
4.2 函数的链式访问
我们将函数的返回值作为另外一个函数的参数的情况,成为函数的链式访问。
如:
①
#include <stdio.h>
int mul(int x, int y)//乘法函数
{
return (x * y);
}
int main()
{
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
printf("%d", mul (x, y));
return 0;
}
在上述代码中,我们将mul函数的返回值,作为了printf函数的参数打印。
②你猜猜打印的数字是多少
printf("%d", printf("%d", printf("%d", 11)));
?这个例子,我是把printf函数的返回值作为了printf本身打印的参数了。
小可爱们,你们分析一下打印的最终结果是多少?
哈哈哈,好了,开玩笑的。让我们好好分析一下。首先,printf函数的返回值是打印的字符的个数。其次,让我们从左往右阅读一下,首先进入第一个printf,它的参数是?printf("%d", printf("%d", 11)),目前因为参数未知打印不了。那么,第二个printf的打印参数为printf("%d", 11)。第三个printf打印的数字为11,这个显而易见。11字符的个数为2,所以第二个printf打印结果为2。因此,第一个printf打印为1。同时,只有11打印完成我们才能知道第二个printf的打印结果,只有第二个打印结果知道,我们才能知道第一个printf函数打印的是啥。综上,打印结果应当为1121。
?
?
此外,还有一个函数递归较为重要,且篇幅较长,我将放在下一个博客中发表。
创作不易,小可爱们,动动你们的小手点个赞再走呗。
?
|