函数的定义:如果函数的定义在main函数之后,函数要在main函数前先进行声明
写一个函数完成两个整数的相加
int Add(int a, int b);//函数的声明 int main() { printf("请您输入a,b的值:"); int a = 0; int b = 0; scanf("%d %d", &a, &b); //计算 //函数的调用(传值调用): int c = Add(a, b); printf("%d\n", c); return 0; } int Add(int a, int b) //函数的定义 本身就是种特殊的声明 但是函数的使用总体来说要满足:先声明后使用 { int c = a + b;//或:return a+b; return c; }
int Add(int a, int b);//函数的声明,一般放在头文件中 int main() { int x = 0; int y = 0; printf("请输入两个整数:"); scanf("%d %d", &x, &y); printf("%d\n", Add(x,y)); return 0; } int Add(int a, int b)//函数的定义 { return a + b; }
函数的声明:告诉编译器 函数名 参数 返回类型 但是具体存在与否函数声明决定不了 //int Add(int a,int b);
函数的声明一般出现在函数的使用之前,先声明后使用
函数的声明一般要放在头文件中
函数的定义:是指函数的具体实现,交代函数的功能实现
未来在工程中,代码比较多,函数一般放在.h文件中声明,放在.c文件中实现
分为三个部分: 1.函数的定义 2.函数的声明 3.函数在main函数中使用 函数的调用
使用时,要包含自己的头文件,#include "add.h",在add.c文件中使用
包含头文件时,自己创建的头文件用" "双引号, 标准库中的头文件用< >兼括号, 函数具有外部链接属性
多人协作 分模块 大家分别去写不同函数的功能 分模块去写
三个文件 三个模块 main函数 函数的声明 函数的定义 只需要用头文件就可以 将加法功能编写成一个库文件,将编写的函数头文件提供就可以了
代码保护:项目名称 配置属性 配置类型 静态库(lib)应用 然后对代码进行编译 然后生成解决方案 Debug文件点进去,得到代码
使用的时候将函数头文件包含 用#pragma comment(lib,"静态库名字")//导入静态库
#pragma comment (lib,"静态库名字") 导入静态库
在函数中可以将静态库独立出来
函数递归
函数可以实现递归
程序调用自身的编程技巧,一个过程或者函数在其定义或说明中直接或间接调用自身的一种方法,通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
递归策略只需要少量的程序就可描述出解题过程中所需要的多次重复计算,大大的减少了程序的代码量
递归的主要方式是:把大事化小
递归的两个必要条件:
1.存在限制条件,当满足这个限制条件的时候,递归便不再继续,不能无条件的递归
2.每次递归调用之后越来越接近这个限制条件
接受一个整形值(无符号),按照顺序打印它的每一位
#include <stdio.h> int main() { //1234 //1234%10=4 //1234/10=123 //123%10=3 //123/10=12 //12%10=2 //12/10=1 //12%10=1 int a = 0; int n = 0; int i = 0; printf("请输入需要逆序的数字:"); scanf("%d", &a); printf("请输入该数字的位数:"); scanf("%d", &n); for (i = 0; i < n; i++) { printf("%d", a % 10); a /= 10; } return 0; }
经历多次循环 不断调用函数 将取得的余位打印出来 分别进行对10取模 然后一个个进行取模 得到最终答案
void Print(int n) {//必须有条件 if (n > 9)//两位数 { Print(n / 10);//要有限制条件,n不断的变小。 //现不断的调用函数将前几位依次打印出来,最后打印最后一位 //不仅要进行递推,还要进行回归 } printf("%d ", n % 10);//不断进行调用 不断进行回归 一个个递推继续向下运行 回归进行打印 return 0;//函数自己反复被调用 } int main() { int num = 0; scanf("%d", &num); Print(num); //Print(1234) //Print(123)+ 4 //Print(12) + 3 //Print(1) + 2 //1 return 0; }
递归只需要少量的程序代码就可以完成任务 大大减少了程序的代码量
递归:递推+回归
层层递推 函数调用后 层层回归 函数栈帧逐个建立逐个销毁
递归的两个必要条件:
1.存在限制条件,当满足这个限制条件的时候,递归便不再继续,不能无条件的递归
2.每次递归调用之后越来越接近这个限制条件
void print(int n) { if (n > 9) { print(n / 10); } printf("%d ", n % 10); } int main() { int n = 0; printf("请您输入一个数:\n"); scanf("%d", &n); print(n); return 0; }
函数之所以能实现调用,递归,都是因为函数在每次调用的时候都会在内存中创建一个函数栈帧
函数栈帧:函数调用需要在C语言内存中申请一片空间,这块空间叫做函数栈帧
函数调用开始,栈帧创建,函数调用结束后,栈帧销毁
编写一个函数不允许创建临时变量 求字符串的长度
strlen函数 包含string头文件 但是要求不创建临时函数
size_t是一种类型,是无符号整形,size_t是为sizeof设计的
size_t类型的数据打印的时候用 %zd 打印
用strlen函数实现
int main() { char arr[] = "abcdadfddffad"; int len = strlen(arr);//size_t //arr传参传递的是数组首元素的地址 size_t数组的长度类型 printf("%d\n", len);//%td return 0; }
模拟实现strlen函数
size_t my_strlen(char* str) { size_t count = 0; //创建临时变量count while (*str != '\0') //数组的最后是\0 依次判断数组元素是否数清结束 { //strlen统计的是\0之前的字符,遇到\0就停止统计 count++; //存放数组中的个数 str++; //指针往后走一步 跳过一个字符指向下一个字符 } return count; //记录数组元素个数 } int main() { char arr[] = "abcsjijsij"; size_t len = my_strlen(arr); printf("%zd\n", len); return 0; } //创建了临时变量count
不用strlen,编写一个函数不允许创建临时变量 求字符串的长度
size_t my_strlen(char* str)//如果不是\0 则它的长度可以用1+my_strlen的长度 1+my_strlen长度 进行递归 { if (*str == '\0') //如果指向\0递归取消 结束 { return 0; } else { return 1 + my_strlen(str + 1); //如果不是\0则进行递归 } } int main() { char arr[] = "abc"; size_t len = my_strlen(arr);//数组名传递的是首个数组元素的地址 printf("%zd\n", len); return 0; }
递归和非递归分别实现求第n个斐波那契数
非递归:
#include<stdio.h> int main() { int n = 0; int a = 1; int b = 1; int c = 1; printf("请您输入您想要查找的斐波那契数:"); scanf("%d", &n); while (n > 2) { c = a + b; a = b; b = c; n--; } printf("%d\n", c); return 0; }
递归:
int fib(int n) { int a = 1; int b = 1; int c = 1; while (n > 2) { c = a + b; a = b; b = c; n--; } return c; } int main() { int a = 0; printf("请您输入您想要查找的斐波那契数: "); scanf("%d", &a); int sum = fib(a); printf("%d\n", sum); return 0; }