1.函数的分类
1.1库函数
库函数的学习,MSDN、Cplusplus网址进行查询,不需要熟记
1.2自定义函数
涉及到交换就是要对进行参数的修改,那么应该采用传址调用的形式
这个函数只是将形参x,y进行了交换,而实参并未发生改变(错误版)传值的方式
(正确)通过传址,指向对应的空间再进行修改
2.函数的参数
相当于函数体当中的局部变量,出了函数体就被销毁了
#include<stdio.h>
//写一个函数实现有序整型的二分查找
int binary_search(int k, int arr[10],int length)
{
int left = 0;
int right = length - 1;
while (left <= right)
{
int middle = (left + right) / 2;
if (k > arr[middle])
{
left = middle + 1;
}
else if (k < arr[middle])
{
right = middle - 1;
}
else
{
return middle;
}
}
return -1;
}
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int k = 0;
scanf("%d", &k);
int length = sizeof(arr) / sizeof(arr[0]);
int ret = binary_search(k, arr, length);
// 找不到返回-1
// 找到返回下标
if (ret != -1)
{
printf("找到了\n,下标是%d",ret);
}
else
{
printf("找不到\n");
}
return 0;
}
数组的传参方式并不是传值调用,数组如果进行传值调用,浪费空间太过于严重
而是传数组名,而数组名代表的是首元素地址,所以数组传参属于是传址调用
所以在计算数组中元素个数(sizeof) 应放在main函数体当中,如果放在二分查找函数内部,数组传参传过来的是一个指针变量,只有4/8个字节
计算出来sz就为1
bool类型只能表示true false
引用bool类型要头文件 #include <stdbool.h>
3.函数的嵌套调用与链式访问
嵌套调用
函数是可以嵌套调用的,但不可嵌套定义
链式访问
一个函数的返回值作为另一个函数的参数被称作链式访问
printf函数的返回值是要打印的字符个数
链式访问的条件是函数要有返回值
printf作为最后一条指令,返回值是字符个数,一共是5个字符,将printf函数的返回值作为Add函数的返回值,不推荐这样书写代码
4.函数的声明与定义
函数声明了,可能不存在(提供一个假的声明)
如果将函数定义在main函数后面,编译器从下往上扫描,未扫描到Add函数,报警告 解决方案:在前面进行函数声明
代码进行模块化划分
add.h模块
进行函数的声明
//函数的声明
int Add(int x, int y);
add.c模块
实现add函数
int Add(int x,int y)
{
return x + y;
}
test模块
#include <stdio.h>
#include "add.h"
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);//30 40
//加法
int sum = Add(a, b);
printf("%d\n", sum);//70
return 0;
}
引用头文件 #include “add.h” 引用头文件的本质就是将头文件中的内容拷贝到当前文件
游戏引擎制作完成后,卖钱,卖给公司的是静态库和头文件,确保公司可以进行使用,但是看不见如何实现的代码,一定程度上保护开发人员
代码分模块化如果将代码编译成静态库,在一定程度上将代码隐藏起来
5.函数的递归(重点)
5.1 什么是递归
程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。
一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,
它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,
递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小
5.2 递归的两个必要条件
1 . 存在限制条件,当满足这个限制条件的时候,递归便不再继续。
2 . 每次递归调用之后越来越接近这个限制条件
递归中常见的报错 Stack overflow 栈溢出
函数的调用发生在栈区,如果没有上述的必要条件就会出现死递归,不断地在栈区开辟空间直到栈溢出
字符数组传参,参数是数组的首元素地址,所以形参要拿指针进行接收
5.3 递归实例
这里的str+1不能写成str++的形式,后置++先传值再++,意味着又将str传过去,无法实现递归调用之后越来越接近这个限制条件
而前置++虽然行的通,但也不推荐前置++,前置++会修改str的值。
5.4 递归与迭代
求第n个斐波那契数。(不考虑溢出)
参考代码:
int fib(int n) {
if (n <= 2)
return 1;
else
return fib(n - 1) + fib(n - 2);
}
但是我们发现有问题;
在使用 fib 这个函数的时候如果我们要计算第50个斐波那契数字的时候特别耗费时间。
为什么呢?
int count = 0;//全局变量
int fib(int n) {
if(n == 3)
count++;
增加一个count计算fib函数中fib(3)计算的次数发现非常大
fib 函数在调用的过程中很多计算其实在一直重复,效率十分低下
提示:
- 许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。
- 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
- 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开
销。