1、why函数?
#include <stdio.h>
int moveToLeft(){
printf("打左转向灯\n");
printf("看左边后视镜\n");
printf("向左打方向盘\n");
printf("踩油门加速\n");
}
int moveToRight(){
printf("打右转向灯\n");
printf("看右边后视镜\n");
printf("向右打方向盘\n");
printf("踩油门加速\n");
}
int main()
{
/*
* 为什么要定义函数
*
* 如果不定义函数:
* 1.重复代码冗余代码过多, 又臭又长
* 2.需求发生变更时需要修改很多代码, 不利于维护
*
* 如果定义函数:
* 1.提高了代码的复用性, 代码变得更简洁
* 2.需求发生变更时只需要修改很少的代码, 有利于维护
*
* 函数的作用:
* 将某些代码封装起来
*/
/*
// 像左边变道
printf("打左转向灯\n");
printf("看左边后视镜\n");
printf("向左打方向盘\n");
// printf("踩油门加速\n");
// 像右边变道
printf("打右转向灯\n");
printf("看右边后视镜\n");
printf("向右打方向盘\n");
printf("踩油门加速\n");
// 像左边变道
printf("打左转向灯\n");
printf("看左边后视镜\n");
printf("向左打方向盘\n");
// printf("踩油门加速\n");
*/
// 向左变道
moveToLeft();
printf("-----------------\n");
// 向右变道
moveToRight();
printf("-----------------\n");
// 向左变道
moveToLeft();
return 0;
}
#include <stdio.h>
int getMax(int num1, int num2){
int max = num1 > num2 ? num1 : num2;
return max;
}
int main()
{
/*
* 函数定义的格式
* 返回值类型 函数名称(形参列表){
* 被封装到函数中的代码;
* }
*
* 初学者如何定义函数
* 1.确定函数的名称(给函数起一个有意义的名称, 让调用者见名知意)
* 注意点: 函数名称也是标识符的一种, 所以也需要遵守标识符的命名规则 字母 数字 下划线 驼峰命名
* 2.确定形参列表(告诉调用者调用时是否需要传递一些辅助的数据)
* 注意点: 形参列表的格式 (数据类型 变量名称, 数据类型 变量名称, ....)
* 数据类型 变量名称 可以有零个或多个
* 3.确定返回值和返回值类型
* 注意点: 返回的数据是什么类型, 返回值类型就写什么类型
* return的作用之一就是将后面的数据返回给函数的调用者
*
*/
int a = 10;
int b = 20;
// int max = a > b ? a : b;
int max = getMax(a, b);
printf("max = %i\n", max);
// int c = 55;
// int d = 60;
// int max2 = c > d ? c : d;
int max2 = getMax(55, 60);
printf("max2 = %i\n", max2);
return 0;
}
#include <stdio.h>
int getAverage(int num1, int num2){
int avg = (num1 + num2) / 2;
return avg;
}
int main()
{
int a = 10;
int b = 20;
// int res = (a + b) / 2;
int res = getAverage(a, b);
printf("average = %i\n", res);
return 0;
}
#include <stdio.h>
// 没有参数的函数
void test(){
printf("test\n");
}
// 有参数的函数
int sum(int a, int b){
return a + b;
}
void say(int age){
printf("age = %i\n", age);
}
char test2(){
return 'a';
}
float test3(){
return 3.14;
}
int main()
{
// 1.函数可以有参数, 也可以没有参数
// 2.函数的参数可以是零个或多个
test();
int res = sum(1, 1);
printf("res = %i\n", res);
say(18);
// 3.函数可以有返回值, 也可以没有返回值
// 如果函数没有返回值, 那么返回值类型写void就可以了
// 4.函数的返回值类型可以是所有C语言类型
printf("test2 = %c\n", test2());
printf("test3 = %f\n", test3());
return 0;
}
#include <stdio.h>
void test(){
printf("test 1111");
}
//void test(){ // 会报重复定义的错误
// printf("test 22222");
//}
//int test(){ // 会报重复定义的错误
// printf("test 33333");
//}
//int test(int a, int b){// 会报重复定义的错误
// printf("test 1111");
//}
//int test1(){
// int say(){ // 会报错
// printf("say 321\n");
// }
// printf("test1\n");
//}
//void change(int num){ // 这里的num,我们称之为形参
// num = 666;
//}
//void test(int num){
// int num = 666;
// printf("num = %i\n", num);
//}
int main()
{
/*
// 1.函数的名称不能相同
// 1.2.哪怕返回值类型不同, 函数名称也不能相同
// 1.3.哪怕形参列表不同, 函数名称也不能相同
// 2.函数不能嵌套定义, 哪怕编译器允许, 也不建议这么干
// void say(){
// printf("say 123");
// }
// say();
test1();
// say();
*/
// // 3.如果是基本类型的数据作为函数的参数, 那么在函数内修改形参, 不会影响外面实参的值
// // int char float double
// int a = 10; // 这里的a我们称之为实参
// printf("调用change函数前:a = %i\n", a); // 10
// change(a);
// printf("调用change函数后:a = %i\n", a); // 10
// 4.在函数内部不能定义和形参同名的变量
// 变量之间的赋值都是拷贝
int a = 10;
int b = a;
b = 666;
printf("a = %i\n", a);
printf("b = %i\n", b);
return 0;
}
2、函数进阶
#include <stdio.h>
//void test(){
// printf("test\n");
//}
// 函数的声明
//void test();
//void test();
//void test();
//void test();
//void test();
int sum(int, int);
int main()
{
/*
* C语言规定:
* 如果将函数的定义写在了函数调用之后, 那么必须在调用之前编写函数的声明
*
* 什么是函数的定义:
* 函数的定义就是函数具体的实现代码, 真正实现了函数功能的代码
*
* 什么是函数的声明:
* 函数的声明就是在调用之前告诉编译器, 我们一定有一个名称叫什么, 接收什么类型参数, 返回值是什么类型的一个函数
* 函数的什么只需将函数定义{前面的代码拷贝即可
*
* 注意点:
* 1.如果不按照C语言的规定在函数调用之前编写函数的什么, 那么在不同编译器下会有不同的运行结果
* GCC编译器可以编译通过, 但是在其它的编译器可能就会报错
* 2.由于函数的声明仅仅是为了告诉编译器, 我们有一个什么函数, 所以函数的声明可以声明多次, 但是函数的实现只能实现一次
* 3.由于函数的声明仅仅是为了告诉编译器, 我们有一个什么函数, 所有函数的什么只要在调用之前声明即可
* 4.由于函数的声明仅仅是为了告诉编译器, 我们有一个什么函数, 所以声明时不用指定形参的名称
* 5.如果函数的返回值类型是int类型, 那么可以不用编写函数的声明(仅仅作为了解)
*/
// void test();
test();
// int sum(int , int);
int res = sum(10, 20);
printf("res = %i\n", res);
return 0;
}
// 函数的定义
void test()
{
printf("test\n");
}
//void test()
//{
// printf("test\n");
//}
int sum(int a, int b){
return a +b;
}
#include <stdio.h>
/*
* 1.main函数是系统自动调用的函数, 我们不能手动调用
* 2.系统在调用main函数的时, 默认会传递两个参数
* argc: 第二个数组保存数据的个数
* argv: 默认保存了一个数据, 这个数据就是当前文件的地址
* 3.argv中保存的元素是可以动态添加的
*
* 4.main函数的return 0 的含义
* 告诉系统当前程序是正常结束的, 如果return返回的不是0, 就代表告诉系统程序不是正常结束的
*
* 暂时只需要知道一点:
* 在企业开发中, 我们是可以通过控制台(CMD)在运行程序的时候给main函数传递参数的就可以了
*/
int main(int argc, const char *argv[])
{
// ["lisi", "zs"]
// 代表数组中有一个元素
// 代表数组中有两个元素
// 默认情况下, 系统在调用main函数的时候, 会给argv这个数组中存放一个元素
// ["C:\Users\Jonathan_Lee\Desktop\C_Lessons\Code\build-76-lesson-Desktop_Qt_5_11_0_MinGW_32bit-Debug\debug\76-lesson.exe"]
printf("argc = %i\n", argc);
printf("argv[0] = %s\n", argv[0]);
printf("argv[1] = %s\n", argv[1]);
printf("argv[2] = %s\n", argv[2]);
return 0;
}
#include <stdio.h>
//// 没有返回值, 没有形参的函数
//void test1(){
// printf("test1\n");
//}
//// 没有返回值, 有形参的函数
//void test2(int age){
// printf("age = %i\n", age);
//}
//// 有返回值, 没有形参的函数
//int test3(){
// return 998;
//}
//// 有返回值, 有形参的函数
//int sum(int a, int b){
// return a + b;
//}
//test4(){
// return 6;
//}
//// 如果没有编写返回值类型, 默认就是int
//test5(){
// return 6.6; // double
//}
int test6(){
return 3.14;
}
int main()
{
/*
* 函数分类:
* 没有返回值, 没有形参的函数
* 没有返回值, 有形参的函数
* 有返回值, 没有形参的函数
* 有返回值, 有形参的函数
*
* 注意点:
* 1.如果没有写函数的返回值类型, 默认就是int类型
* 2.如果函数的返回值类型和实际返回的类型不同, 那么会隐式(自动)转换为返回值类型
*/
// test1();
// test2(666);
// int res = test3();
// printf("res = %i\n", res);
// int res2 = sum(10, 20);
// printf("res2 = %i\n", res2);
// int res = test4();
// printf("res = %i\n", res);
// int res2 = test5();
// printf("res2 = %i\n", res2);
// printf("res2 = %lf\n", res2);
int res = test6();
printf("res = %i\n", res);
printf("res = %lf\n", res);
return 0;
}
3、递归函数
#include <stdio.h>
int test();
int main()
{
/*
* 递归函数:
* 自己搞自己
* 递归可以实现循环的功能, 但是递归的性能比循环差很多
*/
/*
// // 1.定义变量保存用户输入的数据
// int num = -1;
// do{
// // 2.提醒用户如何输入数据
// printf("请输入一个正整数, 以回车结束\n");
// // 3.接收用户输入的数据
// scanf("%i", &num);
// }while(num < 0);
*/
int res = test();
printf("res = %i\n", res);
return 0;
}
// 1.定义一个函数, 用于用户校验
int test(){
// 1.定义变量保存用户输入的数据
int num = -1;
// 2.提醒用户如何输入数据
printf("请输入一个正整数, 以回车结束\n");
// 3.接收用户输入的数据
scanf("%i", &num);
// 4.判断用户输入的时候是合法数据
if(num < 0){
// 用户输入的数据不合法
return test();
}
return num;
}
#include <stdio.h>
int pow(int, int);
int main()
{
/*
* 编写一个函数实现求 B的n次方
* b(n)
* 假设我们要求b(3)次方
* b(0) = 1
* b(1) = b
* b(2) = b * b
* b(3) = b * b * b
*
* b(0) = 1
* b(1) = b(0) * b // 1 * b
* b(2) = b(1) * b // b * b
* b(3) = b(2) * b // b * b * b
*
* 规律: b(n) = b(n-1) * b;
* b(3) = b(3-1) * b;
* b(3) = b(2) * b;
*
* 3(3) = 3 * 3 * 3 = 27
*/
int res = pow(3, 3);
printf("res = %i\n", res);
return 0;
}
// base就代表是b
int pow(int base, int n){
if(n == 0){
return 1;
}else{
return pow(base, n-1) * base;
}
}
#include <stdio.h>
int test(int n);
int main()
{
/*
* 利用递归实现N的阶乘
* 3! = 3 * 2 * 1
* 2! = 2 * 1
* 1! = 1
*
* 和刚才b的n次方同一个世界同一个梦想, 自己总结规律
*
* 1! = 1
* 2! = 1 * 2
* 3! = 1 * 2 * 3
* 4! = 1 * 2 * 3 * 4
*
* 1! = 1
* 2! = 1! * 2
* 3! = 2! * 3
* 4! = 3! * 4
*
* 规律: n! = (n-1)! * n
*/
/*
* 在企业开发中, 一般情况下能够使用递归实现的功能, 都能使用循环实现, 所以一般情况下不会使用递归
* 递归在面试中出现得比较多, 还有就是在文件操作中使用得比较多
*/
// printf("res = %i\n", 1 * 2 * 3 * 4);
int res = test(4);
printf("res = %i\n", res);
return 0;
}
int test(int n){
if(n == 1){
return 1;
}else{
return test(n - 1) * n;
}
}
#include <stdio.h>
int test(int n);
int main()
{
/*
* :
* 有5个人坐在一起,
* 问第5个人多少岁?他说比第4个人大2岁。
* 问第4个人岁数,他说比第3个人大两岁。
* 问第3个人,又说比第2个人大2岁。
* 问第2个人,说比第1个人大2岁。
* 最后问第1个人, 他说是10岁。
* 请问第5个人多大?
*
* 第1个人: 10
* 第2个人: 10 + 2;
* 第3个人: 10 + 2 + 2;
* 第4个人: 10 + 2 + 2 + 2;
* 第5个人: 10 + 2 + 2 + 2 + 2;
*
* 其中第几个人是n, 10就是n的默认值
*
* 规律: (n - 1) + 2;
*/
int res = test(5);
printf("res = %i\n", res);
return 0;
}
int test(int n){
if(n == 1){
return 10;
}else{
return test(n - 1) + 2;
}
}