C语言初阶--函数
目录
1. 函数是什么?
2. C语言中函数的分类
2.1 库函数
2.2 自定义函数
3. 函数的参数
3.1 实际参数(实参)
3.2 形式参数(形参)
4. 函数调用
4.1 传值调用
4.2 传址调用
练习:写一个函数判断一个数是不是素数
练习:写一个函数判断一年是不是闰年
练习:写一个函数,实现一个整型有序数组的二分查找
5. 函数的嵌套调用和链式访问
5.1 嵌套调用
5.2 链式访问
6. 函数的声明和定义
6.1 函数声明
6.2 函数的定义
7. 函数递归
7.1 什么是递归?
7.2 递归的两个必要条件
练习1
补充:函数栈帧的创建和销毁
练习2
7.3 递归与迭代
练习3
练习4
提示
总结
1. 函数是什么?
数学中我们常见到函数的概念。如f(x) = 2 * x + 1。
维基百科中对函数的定义:子程序。
-
在计算机科学中,子程序,是一个大型程序中的某部分代码,由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。
-
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
2. C语言中函数的分类
-
库函数
-
自定义函数
2.1 库函数
为什么有库函数?
开发过程中每个程序员都可能用得到的一些基础功能。为了支持可移植性、提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员软件开发。
如何学习库函数?
https://cplusplus.com/reference/
简单的总结,C语言常用的库函数有:
-
IO函数
-
字符串操作函数
-
字符操作函数
-
内存操作函数
-
时间/日期函数
-
数学函数
-
其它库函数
1、先看文档学习语法(函数名、函数原型、详细介绍、形式参数、返回值、案例、输出、相关函数)
2、上手练习代码
案例strcpy():
#include <stdio.h>
#include <string.h>
int main()
{char arr1[20] = { 0 };char arr2[] = "hello bit";strcpy(arr1, arr2);printf("%s\n", arr1); //hello bitreturn 0;
}
案例memset():
#include <stdio.h>
#include <string.h>
int main()
{char arr[20] = "hello world";memset(arr, 'x', 5);printf("%s\n", arr); //xxxxx worldreturn 0;
}
#include <stdio.h>
#include <string.h>
int main()
{char arr[20] = "hello world";memset(arr+6, 'y', 3);printf("%s\n", arr); //hello yyyldreturn 0;
}
注意:使用库函数,必须包含 #include 对应的头文件。
学习库函数的工具?
-
MSDN(Microsoft Developer Network)
-
https://cplusplus.com/reference/
-
https://en.cppreference.com/w/(英文版)
-
https://zh.cppreference.com/w/(中文版)
2.2 自定义函数
自定义函数和库函数一样,有函数名、返回值类型和函数参数。
但是不一样的是,这些都由我们自己来设计,给了程序员很大的发挥空间。
函数的组成:
ret_type fun_name(para1, *)
{statement; //语句项
}ret_type 返回类型
fun_name 函数名
para1 函数参数(可以有0个,1个或多个)
{}内 函数体/函数的实现
//求两个整数的最大值#include <stdio.h>
//函数的定义
int get_max(int x, int y)
{return (x > y ? x : y);
}int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);//函数的调用int m = get_max(a, b); printf("%d\n", m);return 0;
}
//写一个函数来交换整型变量的内容(下面代码存在问题,没有交换成功)
//当实参传递给形参时,形参是实参的一份临时拷贝。对形参的修改不会影响实参。
#include <stdio.h>
void Swap(int x, int y) //形式参数
{int z = 0;z = x;x = y;y = z;
}int main()
{int a = 0;int b = 0;scanf("%d%d", &a, &b);printf("交换前:a=%d b=%d\n", a, b);//交换Swap(a, b); //a和b叫实参printf("交换后:a=%d b=%d\n", a, b);return 0;
}
通过调试,没有交换的原因:
当实参传递给形参时,形参是实参的一份临时拷贝。对形参的修改不会影响实参。
引入修改值内容:
int main()
{int a = 10;int* p = &a;a = 20; //直接修改*p = 30; //间接修改return 0;
}
再次修改存在问题的代码
#include <stdio.h>
void Swap(int* px, int* py)
{int z = *px; //z=a*px = *py; //a=b*py = z; //b=z
}int main()
{int a = 0;int b = 0;scanf("%d%d", &a, &b);printf("交换前:a=%d b=%d\n", a, b);//交换//Swap(a, b); Swap(&a, &b); printf("交换后:a=%d b=%d\n", a, b);return 0;
}
报错如下:
LNK200_main 已经在test1.obj中定义
LNK116找到一个或多个重定义的符号
原因:
一个工程中,可以有多个.c文件,但是只能有一个main函数。
3. 函数的参数
3.1 实际参数(实参)
实参:真实传给函数的参数。
实参可以是常量、变量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
int c = Add(a + 3, b); //表达式
int c = Add(Add(a, 3), b); //函数
3.2 形式参数(形参)
形参:指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元)。形式参数当函数调用完成后就自动销毁了。因此形式参数只有在函数中有效。
形式参数和实际参数的名字可以相同,也可以不同。
4. 函数调用
4.1 传值调用
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
4.2 传址调用
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。
练习:写一个函数判断一个数是不是素数
未写函数:
//打印100-200之间的素数,素数是只能被1和它本身整除的数
//例如数字7,只能被1和7整除(2,3,4,5,6)
#include <stdio.h>
int main()
{int i = 0;int count = 0;for (i = 100; i <= 200; i++){//判断i是否为素数,是素数就打印(拿2~i-1之间的数字去尝试除以i)int flag = 1; //假设:初始化变量flag=1,等于1时表示是素数int j = 0;for (j = 2; j <= i-1; j++){if (i % j == 0){flag = 0;break;}}if (flag == 1){count++;printf("%d ", i); //101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199}}printf("\ncount = %d\n", count); //21return 0;
}
优化上述代码
eg: m = a * b
eg: 16 = 2 * 8
= 4 * 4
a和b中一定有一个数字<= sqrt(m),sqrt是开平方的意思。
#include <stdio.h>
#include <math.h>
int main()
{int i = 0;int count = 0;for (i = 101; i <= 200; i+=2) //偶数不可能是素数,所以优化一下,从奇数开始,每次+2,得到100-200的所有奇数{//判断i是否为素数,是素数就打印(拿2~i-1之间的数字去尝试除以i)int flag = 1; //假设:初始化变量flag=1,等于1时表示是素数int j = 0;for (j = 2; j <= sqrt(i); j++) //sqrt是数学库函数(开平方的意思),引入头文件math.h{if (i % j == 0){flag = 0;break;}}if (flag == 1){count++;printf("%d ", i); //101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199}}printf("\ncount = %d\n", count); //21return 0;
}
写函数:
//写一个函数判断一个数是不是素数
#include <stdio.h>
#include <math.h>
int is_prime(int n)
{int j = 0;for (j = 2; j <= sqrt(n); j++) //sqrt是数学库函数(开平方的意思),引入头文件math.h{if (n % j == 0){return 0;}}return 1;
}int main()
{int i = 0;int count = 0;for (i = 101; i <= 200; i+=2) //偶数不可能是素数,所以优化一下,从奇数开始,每次+2,得到100-200的所有奇数{//判断i是否为素数,是素数就打印(拿2~i-1之间的数字去尝试除以i)if (is_prime(i)){printf("%d ", i); //101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199count++;}}printf("\ncount = %d\n", count); //21return 0;
}
练习:写一个函数判断一年是不是闰年
未写函数:
//打印1000-2000年之间的闰年,闰年的规则:1、能被4整除并且不能被100整除的是闰年。2、能被400整除的是闰年
#include <stdio.h>
int main()
{int year = 0;for (year = 1000; year <= 2000; year++){//判断year是不是闰年if (year%4 == 0){if (year%100 != 0){printf("%d ", year);}}if (year%400 == 0){printf("%d ", year);}}return 0;
}
//1004 1008 1012 1016 1020 1024 1028 1032 1036 1040 1044 1048 1052 1056 1060 1064 1068 1072 1076 1080 1084 1088 1092 1096 1104 1108 1112 1116 1120 1124 1128 1132 1136 1140 1144 1148 1152 1156 1160 1164 1168 1172 1176 1180 1184 1188 1192 1196 1200 1204 1208 1212 1216 1220 1224 1228 1232 1236 1240 1244 1248 1252 1256 1260 1264 1268 1272 1276 1280 1284 1288 1292 1296 1304 1308 1312 1316 1320 1324 1328 1332 1336 1340 1344 1348 1352 1356 1360 1364 1368 1372 1376 1380 1384 1388 1392 1396 1404 1408 1412 1416 1420 1424 1428 1432 1436 1440 1444 1448 1452 1456 1460 1464 1468 1472 1476 1480 1484 1488 1492 1496 1504 1508 1512 1516 1520 1524 1528 1532 1536 1540 1544 1548 1552 1556 1560 1564 1568 1572 1576 1580 1584 1588 1592 1596 1600 1604 1608 1612 1616 1620 1624 1628 1632 1636 1640 1644 1648 1652 1656 1660 1664 1668 1672 1676 1680 1684 1688 1692 1696 1704 1708 1712 1716 1720 1724 1728 1732 1736 1740 1744 1748 1752 1756 1760 1764 1768 1772 1776 1780 1784 1788 1792 1796 1804 1808 1812 1816 1820 1824 1828 1832 1836 1840 1844 1848 1852 1856 1860 1864 1868 1872 1876 1880 1884 1888 1892 1896 1904 1908 1912 1916 1920 1924 1928 1932 1936 1940 1944 1948 1952 1956 1960 1964 1968 1972 1976 1980 1984 1988 1992 1996 2000
优化
#include <stdio.h>
int main()
{int year = 0;for (year = 1000; year <= 2000; year++){//判断year是不是闰年if (((year%4 == 0) && (year%100 != 0)) || (year%400 == 0)){printf("%d ", year);}}return 0;
}
写函数:
//写一个函数判断一年是不是闰年
//是闰年返回1,非闰年返回0
#include <stdio.h>
int is_leap_year(int y)
{if (((y%4 == 0) && (y%100 != 0)) || (y%400 == 0)){return 1;}else{return 0;}
}int main()
{int year = 0;for (year = 1000; year <= 2000; year++){//判断year是不是闰年if (is_leap_year(year)){printf("%d ", year);}}return 0;
}
练习:写一个函数,实现一个整型有序数组的二分查找
#include <stdio.h>
int binary_search(int arr[], int k, int sz)
{int left = 0;int right = sz - 1;while (left <= right){int mid = left + (right-left)/2;if (arr[mid] < k){left = mid + 1;}else if (arr[mid] > k){right = mid - 1;}else{return mid; //找到了返回下标}}return -1; //找不到
}int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int k = 7;int sz = sizeof(arr) / sizeof(arr[0]);//找到了,返回下标;找不到,返回-1int ret = binary_search(arr, k, sz);if (ret == -1){printf("找不到");}else{printf("找到了,下标是:%d\n", ret); //找到了,下标是:6}return 0;
}
错误的示范:
数组传参实际上传递的是数组首元素的地址,而不是整个数组。所以在函数内部计算一个函数参数部分的数组元素个数是不靠谱的。
二分查找法不会的可以自行百度,或者后续有时间出个详解。
5. 函数的嵌套调用和链式访问
函数和函数之间可以根据实际的需求进行组合,也就是互相调用的。
5.1 嵌套调用
#include <stdio.h>
void new_line()
{printf("hehe\n");
}
void three_line()
{int i = 0;for (i = 0; i < 3; i++){new_line();}
}
int main()
{three_line();return 0;
}
函数可以嵌套调用,但不能嵌套定义。
//不能嵌套定义
int Add(int x, int y)
{return x + y;int Sub(int x, int y) //error{return x - y;}
}int main()
{return 0;
}
5.2 链式访问
把一个函数的返回值作为另一个函数的参数。
#include <stdio.h>
#include <string.h>
int main()
{int len = strlen("abcdef");printf("%d\n", len); //6//链式访问printf("%d\n", strlen("abcdef")); //6,将strlen()函数的返回值(size_t类型)作为参数传给printf()return 0;
}
//经典案例
#include <stdio.h>
int main()
{printf("%d, printf("%d", printf("%d", 43))"); //4321return 0;
}
函数不写返回值的返回类型时,默认返回类型是int类型。
//不推荐,下面的代码在一些编译器上返回的是函数中执行过程中最后一条指令执行的结果,5
int Add(int x, int y)
{printf("hehe\n");
}
函数定义时没有参数,就不用特意去传参。(传参,函数也不会调用)
//明确地说明,main函数不需要参数,本质上main函数是有参数的
int main(void)
{return 0;
}
//main函数有3个参数
int main(int argc, char* argv[], char *envp[])
{return 0;
}
6. 函数的声明和定义
6.1 函数声明
告诉编译器有一个函数叫什么,参数类型是什么,返回类型是什么。但是具体是否存在,函数声明决定不了。
函数的声明一般出现在函数的使用之前,要满足先声明后使用。
函数的声明一般要放在头文件中的。
#include <stdio.h>int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);//加法int sum = Add(a, b);printf("%d\n", sum);return 0;
}//函数的定义
int Add(int x, int y)
{return x + y;
}
将函数定义在main函数后,会报如下错误:
Warning:“Add”未定义;假设外部返回int
解决:
//一般也不如下使用#include <stdio.h>
//函数的声明
int Add(int x, int y);int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);//加法int sum = Add(a, b);printf("%d\n", sum);return 0;
}//函数的定义
int Add(int x, int y)
{return x + y;
}
6.2 函数的定义
函数的定义是指函数的具体实现,交代函数的功能实现。
//真正情况下如下使用://add.h
#pragma once //防止头文件被重复包含
//函数的声明
int Add(int x, int y);
//sub.h
#pragma once //防止头文件被重复包含
//函数的声明
int Sub(int x, int y);//add.c
//函数的定义
int Add(int x, int y)
{return x + y;
}
//sub.c
int Sub(int x, int y)
{return x - y;
}//test.c
#include <stdio.h>#include "add.h"
#include "sub.h"
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b); //20 10//加法int sum = Add(a, b);printf("%d\n", sum); //30//减法int ret = Sub(a, b);printf("%d\n", ret); //10return 0;
}
//其中的add.h与add.c分别为模块
初学编程时,觉得把所有的代码写到一个文件中最方便。但是在公司里不是这样写代码的。
原因:1、协作的角度;2、功能模块化
非本节重点内容:
假设场景(勿要当真,当然可以反编译):假如A程序员编写了一段加法代码,想变卖给B公司换钱,但并不想透露所有的源码,则可将自己的add.h和add.c编译后的静态库(add.lib)给B公司。
add.h:告诉B公司如何使用函数。
add.c :函数真正的实现。
A程序员
//add.h
#pragma once //防止头文件被重复包含
//函数的声明
int Add(int x, int y);//add.c
//函数的定义
int Add(int x, int y)
{return x + y;
}//test.c
#include <stdio.h>#include "add.h"int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b); //20 10//加法int sum = Add(a, b);printf("%d\n", sum); //30return 0;
}
B公司
//A程序员给B公司的add.h
#pragma once //防止头文件被重复包含
//函数的声明
int Add(int x, int y);//将add.c编译成add.lib,里面的文件内容是编译后的二进制,达到隐藏的功能
//A程序员给B公司的add.lib
int Add(int x, int y)
{return x + y;
}//B公司自己实现的add.c
#include <stdio.h>#include "add.h"
//导入静态库,不导入会报错(还会有依赖,暂且不说)
#pragma comment(lib, "add.lib")
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b); //加法int sum = Add(a, b);printf("%d\n", sum); return 0;
}
上面场景的实现,编译需要使用VS,非VScode(编辑器)
-
VS Code是一个轻量级的代码编辑器,支持语法高亮、智能代码补全、自定义快捷键、代码片段以及代码重构等基本编辑功能,同时还支持调试和内置Git版本控制功能。它主要用于编写和调试代码,特别适合Web开发、Node.js开发以及各种脚本语言的支持。
-
VS是一个全功能的集成开发环境(IDE),除了包括VS Code的所有功能外,还提供了项目模板、项目管理、自动化构建、单元测试、性能分析等更全面的开发工具。它不仅支持前端和后端的开发,还支持数据库、云服务、移动应用开发等,是一个全面的开发解决方案。
7. 函数递归
7.1 什么是递归?
程序调用自身的编程技巧称为递归。
递归作为一种算法,在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。
递归策略:只需少量的程序就可描述出解题过程中所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小
7.2 递归的两个必要条件
存在限制条件,当满足这个限制条件时,递归便不再继续。
每次递归调用后越来越接近这个限制条件。
练习1
接收一个整型值(无符号),按照顺序打印它的每一位。例如:
输入1234,输出1 2 3 4
分析:
1234%10 余4
1234/10 商123123%10 余3
123/10 商1212%10 余2
12/10 商11%10 余1
1/10 商0最后num 0
#include <stdio.h>
int main()
{unsigned int num = 0;scanf("%u", &num); //%d打印有符号的整数,会有正负数;%u打印无符号的整数while (num){printf("%d ", num%10); //4 3 2 1,未符合要求,使用另外的方法 num = num / 10;}return 0;
}
递归分析:
print(1234)
print(123) 4
print(12) 3 4
print(1) 2 3 4
//递归实现
#include <stdio.h>void print(unsigned int n)
{if (n > 9){print(n / 10); }printf("%d ", n % 10);
}
int main()
{unsigned int num = 0;scanf("%u", &num); //%d打印有符号的整数,会有正负数;%u打印无符号的整数print(num); //功能:接收一个整型值(无符号),按照顺序打印它的每一位return 0;
}
如果缺少if条件语句,则会出现死递归(栈溢出Stack overflow)
如下图调试时报错
内存图:
如何解决栈溢出?(层次太深也会导致栈溢出)
1、将递归改为非递归。
2、使用static对象替代nonstatic局部对象。在递归函数设计中,可以使用static对象替代nonstatic局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放nonstatic对象的开销,而且static对象还可以保存递归调用的中间状态,并且可为各个调用层所访问。
补充:函数栈帧的创建和销毁
【函数栈帧的创建和销毁】函数栈帧的创建和销毁_哔哩哔哩_bilibili
科普概念如下:
寄存器:eax、ebx、ecx、edx、esp、ebp
esp、ebp(存放地址,用来维护栈区)
三者函数的调用关系:
练习2
编写函数不允许创建临时变量,求字符串长度。
模拟实现strlen,求字符串长度:
#include <stdio.h>
//int my_strlen(char str[]) //参数部分写成数组的形式
int my_strlen(char* str) //参数部分写成指针的形式
{int count = 0; //计数,临时变量while (*str != '\0'){count++;str++; //找下一个字符}return count;
}
int main()
{char arr[] = "abc"; //[a b c \0]//char*,存放地址,指针变量接收int len = my_strlen(arr);printf("%d\n", len); //3return 0;
}
递归求解:编写函数不允许创建临时变量,求字符串长度。
分析:
my_strlen("abc")
1 + my_strlen("bc")
1 + 1 + my_strlen("c")
1 + 1 + 1 + my_strlen("")
1 + 1 + 1 + 0
#include <stdio.h>
int my_strlen(char* str)
{if (*str != '\0')return 1 + my_strlen(str+1);elsereturn 0;
}
int main()
{char arr[] = "abc"; //[a b c \0]//char*,存放地址,指针变量接收int len = my_strlen(arr);printf("%d\n", len); //3return 0;
}
7.3 递归与迭代
练习3
求n的阶乘。
分析:
当n<=1,Fac(n) = 1;
当n>1,Fac(n) = n * Fac(n-1);5! = 5*4*3*2*1 = 5*4!
//递归实现
#include <stdio.h>
int fac(int n)
{if (n <= 1)return 1;elsereturn n * fac(n-1);
}
int main()
{int n = 0;scanf("%d", &n);int ret = fac(n);printf("ret = %d\n", ret);return 0;
}
//循环实现-非递归
#include <stdio.h>
int fac(int n)
{int i = 0;int ret = 1;for (i = 1; i <= n; i++){ret *= i; //ret = ret * i}
}
int main()
{int n = 0;scanf("%d", &n);int ret = fac(n);printf("ret = %d\n", ret);return 0;
}
练习4
求第n个斐波那契数
斐波那契数列:1 1 2 3 5 8 13 21 34 55····
分析:
当n<=2,Fib(n) = 1;
当n>2,Fib(n) = Fib(n-1) + Fib(n-2);
//递归实现,效率低
#include <stdio.h>
int Fib(int n)
{if (n <=2 )return 1;elsereturn Fib(n-1) + Fib(n-2);
}
int main()
{int n = 0;scanf("%d", &n);int ret = Fib(n);printf("%d\n", ret);return 0;
}
//迭代实现,效率高(均不考虑溢出问题)
#include <stdio.h>
int Fib(int n)
{int a = 1;int b = 1;int c = 1;while (n >= 3){c = a + b;a = b;b = c;n--;}return c;
}
int main()
{int n = 0;scanf("%d", &n);int ret = Fib(n);printf("%d\n", ret);return 0;
}
提示
1、许多问题是以递归的形式来解释的,这只是因为它比非递归的形式更为清晰。
2、但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
3、当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时的开销。
函数递归的经典题目:(自主研究)
-
汉诺塔问题(B站:比特大博哥)
-
青蛙跳台阶问题
总结
(最近比较忙,没有更新)
今天就暂且更新至此吧,期待下周再会。如有错误还请不吝赐教。如果觉得对您学习有所帮助,还请留下你的支持,以防下次失踪了嗷。
作者更新不易,免费关注别手软。
相关文章:
C语言初阶--函数
目录 1. 函数是什么? 2. C语言中函数的分类 2.1 库函数 2.2 自定义函数 3. 函数的参数 3.1 实际参数(实参) 3.2 形式参数(形参) 4. 函数调用 4.1 传值调用 4.2 传址调用 练习:写一个函数判断一个…...
探索基于机器学习的信用评分:从数据到洞察
友友们好! 我的新专栏《Python进阶》正式启动啦!这是一个专为那些渴望提升Python技能的朋友们量身打造的专栏,无论你是已经有一定基础的开发者,还是希望深入挖掘Python潜力的爱好者,这里都将是你不可错过的宝藏。 在这个专栏中,你将会找到: ● 深入解析:每一篇文章都将…...
Ubuntu 24.04 LTS 通过 docker desktop 安装 seafile 搭建个人网盘
准备 Ubuntu 24.04 LTSUbuntu 空闲硬盘挂载Ubuntu 安装 Docker Desktop [我的Ubuntu服务器折腾集](https://blog.csdn.net/jh1513/article/details/145222679。 安装 seafile 参考资料 Docker安装 Seafile OnlyOffice 并配置OnlyOffice到Seafile,实现在线编辑…...
【Golang 面试题】每日 3 题(三十六)
✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/UWz06 📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏…...
Linux虚拟机安装与FinalShell使用:探索Linux世界的便捷之旅
文章目录 软件准备安装 VMware 虚拟机下载CentOS 光盘镜像文件选择适合的 CentOS 版本选择合适的镜像文件 本教程工具版本 第一部分:安装 Linux 虚拟机1. 启动 VMware 并创建新虚拟机2. 默认硬件兼容性设置3. 安装操作系统的设置4. 选择操作系统类型与版本5. 为虚拟…...
leetcode19-删除链表的第n结点
leetcode 19 思路 要删除倒数第n个元素,那么就要找到倒数第n1个元素,那么我们需要两个指针来记录,首先快指针需要先走n1步,然后快慢指针一起进行移动,直到快指针为null的时候,此时慢指针恰好走到倒数第n…...
多学科视角下探索开源Github、Git初步学习
Think 1.Github 作为现今最主流的代码托管平台、协作平台甚至是“社交平台”,本身是闭源的。一方面,它是和大多数开发者连接最紧密的开源阵地,另一方面,拥有传统“黑客精神”的人认为将用户身份绑定这样一个闭源平台上恰恰与…...
新星杯-ESP32智能硬件开发--ESP32的I/O组成-系统中断矩阵
本博文内容导读📕🎉🔥 ESP32开发板的中断矩阵、功能描述与实现、相关API和示例程序进行介绍 ESP32中断矩阵将任一外部中断源单独分配到每个CPU的任一外部中断上,提供了强大的灵活性,能适应不同的应用需求。 ESP32中断主…...
Android 右键后无Java class创建
Android studio 创建java class : 最近几个月用Android studio 开发,因为电脑设置了一个新的用户使用,原来的android studio,打开之前的正常的项目总是报一些奇奇怪怪的错误,就重新安装了最新的版本 问题描述 但是新的android s…...
leetcode-买卖股票问题
309. 买卖股票的最佳时机含冷冻期 - 力扣(LeetCode) 动态规划解题思路: 1、暴力递归(难点如何定义递归函数) 2、记忆化搜索-傻缓存法(根据暴力递归可变参数确定缓存数组维度) 3、严格表结构依…...
如何通过 Apache Airflow 将数据导入 Elasticsearch
作者:来自 Elastic Andre Luiz 了解如何通过 Apache Airflow 将数据导入 Elasticsearch。 Apache Airflow Apache Airflow 是一个旨在创建、安排(schedule)和监控工作流的平台。它用于编排 ETL(Extract-Transform-Load࿰…...
LDPC (Low-Density Parity-Check) 码min_sum、n_0、block_length 和 rate参数
1. min_sum 1; min_sum 是与 最小和解码算法(Min-Sum Decoding Algorithm)相关的参数。最小和解码算法是 LDPC 码的一种常用解码方法,主要通过传递信号的信息在接收端进行解码。此参数表示最小和算法中的缩放因子。 在 LDPC 解码过程中&am…...
基于javaweb的SpringBoot景区旅游管理系统设计和实现(源码+文档+部署讲解)
个人名片 🔥 源码获取 | 毕设定制| 商务合作:《个人名片》 ⛺️心若有所向往,何惧道阻且长 文章目录 个人名片运行环境技术栈适用功能说明使用说明 运行环境 Java≥8、MySQL≥5.7 1.运行环境:最好是java jdk 1.8,我们在这个平台…...
(二)afsim第三方库编译(qt编译)
注意:源码编译的路径不能有中文否则报错,压缩包必须用官网下载的xz格式解压的才可以,否则sudo ./configure命令找不到 先编译openssl3.1.1软件包,否则编译的qt库将不支持network,相关库的编译(上文(一&…...
重学SpringBoot3-Spring Retry实践
更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞??收藏评论 重学SpringBoot3-Spring Retry实践 1. 简介2. 环境准备3. 使用方式 3.1 注解方式 基础使用自定义重试策略失败恢复机制重试和失败恢复效果注意事项 3.2 编程式使用3.3 监听重试过程 监…...
极域电子教室破解(JiyuTrainer)
JiyuTrainer下载 byebye极域电脑安装包也可以使用 如果只玩单机游戏最简单的办法就是拔网线 另一种办法安装360卫士通过360卫安全卫士上网设置来进行禁用JiyuTrainer网络跟拔网线一样...
Oracle数据库传统审计怎么用
Oracle数据库传统审计怎么用 审计功能开启与关闭By Session还是By AccessWhenever Successful数据库语句审计数据库对象审计查看审计策略和记录Oracle数据库审计功能分为传统审计(Traditional Auditing)和统一审计(Unified Auditing)。统一审计是从Oracle 12c版本开始引入的…...
windows 搭建flutter环境,开发windows程序
环境安装配置: 下载flutter sdk https://docs.flutter.dev/get-started/install/windows 下载到本地后,随便找个地方解压,然后配置下系统环境变量 编译windows程序本地需要安装vs2019或更新的开发环境 主要就这2步安装后就可以了࿰…...
基于SpringBoot的健身房管理系统【源码+文档+部署讲解】
系统介绍 基于SpringBootVue实现的健身房管理系统采用前后端分离架构方式,系统设计了管理员、会员、员工三种角色,系统实现了用户登录与注册、个人中心、会员管理、员工管理、会员卡管理、会员卡类型管理、教练信息管理、解聘管理、健身项目管理、指导项…...
2.slf4j入口
文章目录 一、故事引入二、原理探究三、SLF4JServiceProvider四、总结 一、故事引入 故事要从下面这段代码说起 public class App {private static final Logger logger LoggerFactory.getLogger(App.class);public static void main( String[] args ) throws Exception {lo…...
sql_实用查询语句模版
1. 查询某个字段是否为必填项 SQL 查询模板 SELECT COLUMN_NAME,IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME YourTableNameAND COLUMN_NAME YourColumnName;说明: INFORMATION_SCHEMA.COLUMNS 表包含了所有数据库中表的列信息。IS_NULLABL…...
Nginx反向代理架构介绍
Nginx反向代理架构是一种强大的服务器架构模式,它位于用户和原始服务器之间,接收用户的请求并将其转发到一个或多个后端服务器,然后将从后端服务器获取的响应返回给用户,就好像这些内容都是由代理服务器本身直接提供的一样。以下是…...
Mysql MVCC
MVCC 什么是MVCC MVCC(多版本并发控制,Multi-Version Concurrency Control) 是一种用于数据库管理系统(DBMS)中的并发控制机制,它允许多个事务同时执行而不互相阻塞,并通过创建数据的多个版本…...
JavaEE之CAS
上文我们认识了许许多多的锁,此篇我们的CAS就是从上文的锁策略开展的新概念,我们来一探究竟吧 1. 什么是CAS? CAS: 全称Compare and swap,字⾯意思:“比较并交换”,⼀个CAS涉及到以下操作: 我们假设内存中…...
Flink CDC 使用实践以及遇到的问题
背景 最近公司在做一些业务上的架构调整,有一部分是数据从mysql采集到Starrocks,之前的一套方法是走 debezium 到 puslar 到 starrocks,这一套下来比较需要配置很多东西,而且出现问题以后,需要修改很多配置,而且现阶段…...
idea上git log面板的使用
文章目录 各种颜色含义具体的文件的颜色标签颜色🏷️ 节点和路线 各种颜色含义 具体的文件的颜色 红色:表示还没有 git add 提交到暂存区绿色:表示已经 git add 过,但是从来没有 commit 过蓝色:表示文件有过改动 标…...
03.选择排序
一、题目思路 选择排序是一种简单直观的排序算法。它的工作原理是:首先在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(或最大ÿ…...
麒麟V10系统上安装Oracle
以下是在麒麟V10系统上安装Oracle数据库的详细步骤: 安装前准备 检查系统版本:使用uname -a、cat /etc/os-release等命令检查服务器是麒麟V10系统。 配置固定IP和本地yum源: 挂载麒麟V10的iso文件到/mnt目录,如mount -o loop Ky…...
PyTorch 神经协同过滤 (NCF) 推荐系统教程
目录 教程概述1. 神经协同过滤模型概述NCF 模型的主要组成部分: 2. 数据加载与预处理3. 定义神经协同过滤模型4. 训练模型5. 模型评估6. 推荐物品7. 完整示例8. 总结 在本教程中,我们将使用 PyTorch 实现一个神经协同过滤(Neural Collaborat…...
日志收集Day001
1.ElasticSearch 作用:日志存储和检索 2.单点部署Elasticsearch与基础配置 rpm -ivh elasticsearch-7.17.5-x86_64.rpm 查看配置文件yy /etc/elasticsearch/elasticsearch.yml(这里yy做了别名,过滤掉空行和注释行) yy /etc/el…...
【氮化镓】香港科技大学陈Kevin-单片集成GaN比较器
一、引言(Introduction) GaN HEMT的重要性 文章开篇便强调了氮化镓(GaN)高电子迁移率晶体管(HEMT)在下一代功率转换系统中的巨大潜力。GaN HEMT具备高开关频率、低导通电阻、高击穿电压以及宽工作温度范围等优势,使其成为功率电子领域的热门研究对象。这些特性使得GaN…...
LDD3学习9--数据类型和定时器
这部分对应的是第七章和第十一章,因为内容也不是很多,就一起写了。里面的内容基本上就是一个个的点,所以也就一个个点简单总结一下。 1 数据类型 1.1 数据长度 不同操作系统类型长度可能不一样,看图的话最好用u8,u16&…...
性价比1.2V电压基准替代
前言: 小于2V的电压基准比较少,且价格稍贵,对于要求不高的场合,1117可以替代使用,温度系数低于 100ppm/C, 价格便宜。 1117是线性稳压器的一种,一般情况下,输出电压可调。 如下述的1117…...
【青蛙过河——思维】
题目 图解 代码 #include <bits/stdc.h> using namespace std; const int N 1e510; int n, x; int h[N]; bool check(int mid) {for(int i 1; i mid - 1 < n; i)if(h[i mid - 1] - h[i - 1] < 2 * x) return false;return true; } int main() {cin >> …...
【数据库】MySQL数据库SQL语句汇总
目录 1.SQL 通用语法 2.SQL 分类 2.1.DDL 2.2.DML 2.3.DQL 2.4.DCL 3.DDL 3.1.数据库操作 3.1.1.查询 3.1.2.创建 3.1.3.删除 3.1.4.使用 3.2.表操作 3.2.1.查询 3.2.2.创建 3.2.3.数据类型 3.2.3.1.数值类型 3.2.3.2.字符串类型 3.2.3.3.日期时间类型 3.2…...
Vue3 Element-Plus el-tree 右键菜单组件
参考代码:实现Vue3Element-Plus(tree、table)右键菜单组件 这篇文章的代码确实能用,但是存在错误,修正后的代码: <template><div style"text-align: right"><el-icon size"12" color"#…...
学成在线_内容管理模块_创建模块工程
学成在线模块工程 1.各个微服务依赖基础工程2.每个微服务都是一个前后端分离的项目3.xuecheng-plus-content:内容管理模块工程xuecheng-plus-content-modelxuecheng-plus-content-servicexuecheng-plus-content-api 1.各个微服务依赖基础工程 2.每个微服务都是一个前…...
Swift 专题二 语法速查
一 、变量 let, var 变量是可变的,使用 var 修饰,常量是不可变的,使用 let 修饰。类、结构体和枚举里的变量是属性。 var v1:String "hi" // 标注类型 var v2 "类型推导" let l1 "标题" // 常量class a {…...
vue2配置跨域后请求的是本机
这个我来说明一下,因为我们公司的后端设置解决了跨域问题,所以我有很久没有看相关的内容了,然后昨天请求了需要跨域的接口,请求半天一直不对,浏览器显示的是本机地址,我以为是自己配置错了,后面…...
Linux 音视频入门到实战专栏(视频篇)视频编解码 MPP
文章目录 一、MPP 介绍二、获取和编译RKMPP库三、视频解码四、视频编码 沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍如何调用alsa api来进行音频数据的播放和录制。 一、MPP 介绍 瑞芯微提供的媒体处理软件平台…...
IT程序设计文档,软件需求设计文档,详细设计模板(Word原件)
1引言 1.1编写目的 1.2项目背景 1.3参考材料 2系统总体设计 2.1整体架构 2.2整体功能架构 2.3整体技术架构 2.4设计目标 2.5.1总体原则 2.5.2实用性和先进性 2.5.3标准化、开放性、兼容性 2.5.4高可靠性、稳定性 2.5.5易用性 2.5.6灵活性和可扩展性 2.5.7经济性…...
画流程图 代码生成流程图 流程图自动运行
一:在线平台 典藏 drawio:完全免费;可拆入代码生成;使用方法 Kimi drawio生成流程图:Kimi里面生成Mermaid格式——>生成代码并复制——>进入drawio里面点插入"号"——>高级——>Mermaid——…...
庄小焱——2024年博文总结与展望
摘要 大家好,我是庄小焱。岁末回首,2024 年是我在个人成长、博客创作以及生活平衡方面收获颇丰的一年。这一年的经历如同璀璨星辰,照亮了我前行的道路,也为未来的发展奠定了坚实基础。 1. 个人成长与突破 在 2024 年,…...
Unity3d 实时天气系统基于UniStorm插件和xx天气API实现(含源码)
前言 实时天气在Unity3d三维数字沙盘中的作用非常重要,它能够增强虚拟环境的真实感和互动性,实时天气数据的应用可以提供更为精准和直观的天气信息支持,如果真实的数据加上特效、声音和模型反馈会提高产品档次,提高真实感。 目前…...
【学习总结|DAY032】后端Web实战:登录认证
在 Web 后端开发中,登录认证是保障系统安全和用户数据隐私的关键环节。本文将结合实际开发案例,深入探讨登录功能与登录校验的实现思路和技术细节,希望能帮助读者更好地掌握这一重要知识点。 一、登录功能实现 1.1 思路分析 登录功能的核心…...
在 C++ 中实现调试日志输出
在 C 编程中,调试日志对于定位问题和优化代码至关重要。有效的调试日志不仅能帮助我们快速定位错误,还能提供有关程序运行状态的有价值的信息。本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳。 1. 使用 #ifdef _DEBUG…...
2-Kbengine+Unity3D多人在线游戏DEMO源码架构分析
2-Kbengine+Unity3D多人在线游戏DEMO源码架构分析 目录 一、服务器端 1、编写并生成我们的服务器端和客户端通用的游戏协议 2、 认识Entity实体 3、 官方DEMO-kbengine_demos_assets分析 二、 客户端...
Android系统开发(八):从麦克风到扬声器,音频HAL框架的奇妙之旅
引言:音浪太强,我稳如老 HAL! 如果有一天你的耳机里传来的不是《咱们屯里人》,而是金属碰撞般的杂音,那你可能已经感受到了 Android 音频硬件抽象层 (HAL) 出问题的后果!在 Android 音频架构中,…...
使用nginx搭建通用的图片代理服务器,支持http/https/重定向式图片地址
从http切换至https 许多不同ip的图片地址需要统一进行代理 部分图片地址是重定向地址 nginx配置 主站地址:https://192.168.123.100/ 主站nginx配置 server {listen 443 ssl;server_name localhost;#ssl证书ssl_certificate ../ssl/ca.crt; #私钥文件ssl_ce…...
Java-数据结构-二叉树习题(1)
对于二叉树的学习,主要的还是得多多练习~毕竟二叉树属于新的知识,并且也并不是线性结构,再加上经常使用递归的方法解决二叉树的问题,所以代码的具体流程还是无法看到的,只能通过画图想象,所以还是必须多加练…...