【C++ 四】函数、指针
函数、指针
文章目录
- 函数、指针
- 前言
- 1 函数
- 1.1 概述
- 1.2 函数定义
- 1.3 函数调用
- 1.4 值传递
- 1.5 函数常见样式
- 1.6 函数声明
- 1.7 函数分文件编写
- 1.8 函数默认参数
- 1.9 函数占位参数
- 1.9 函数重载
- 1.9.1 函数重载概述
- 1.9.2 函数重载注意事项
- 2 指针
- 2.1 指针基本概念
- 2.2 指针变量定义和使用
- 2.3 指针所占内存空间
- 2.4 空指针和野指针
- 2.5 const 修饰指针
- 2.6 指针和数组
- 2.7 指针和函数
- 2.8 指针、数组、函数
- 总结
前言
本文包含函数概述、函数定义、函数调用、值传递、函数常见样式、函数声明、函数份文件编写、函数默认参数、函数占位参数、函数重载、指针基本概念、指针变量定义和使用、指针所占内存空间、空指针和野指针、const修饰指针、指针和数组、指针和函数、指针数组函数。
1 函数
1.1 概述
作用: 将一段经常使用的代码封装起来,减少重复代码
一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能
1.2 函数定义
函数的定义一般主要有5个步骤:
(1)、返回值类型
(2)、函数名
(3)、参数表列
(4)、函数体语句
(5)、return 表达式
语法:
返回值类型 函数名 (参数列表)
{函数体语句return表达式}
(1)、返回值类型 :一个函数可以返回一个值。在函数定义中
(2)、函数名:给函数起个名称
(3)、参数列表:使用该函数时,传入的数据
(4)、函数体语句:花括号内的代码,函数内需要执行的语句
(5)、return 表达式: 和返回值类型挂钩,函数执行完后,返回相应的数据
示例: 定义一个加法函数,实现两个数相加
// 返回值类型:int
// 函数名:add
// 参数列表:(int num1, int num2)
// 函数体语句:int sum = num1 + num2;
// return 表达式:return sum;
int add(int num1, int num2)
{int sum = num1 + num2;return sum;
}
1.3 函数调用
功能: 使用定义好的函数
语法: 函数名(参数)
#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间// 函数定义
int add(int num1, int num2) // 定义中的num1,num2称为形式参数,简称形参
{int sum = num1 + num2;return sum;
}int main() {int a = 10;int b = 10;// 调用add函数int sum = add(a, b); // 调用时的a,b称为实际参数,简称实参cout << "sum = " << sum << endl; // 20cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

1.4 值传递
(1)、所谓值传递,就是函数调用时实参将数值传入给形参
(2)、值传递时,如果形参发生,并不会影响实参
#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间// 定义函数,实现两个数字进行交换
void swap(int num1, int num2) // 如果函数不需要返回值,声明的时候可以写void
{cout << "交换前:" << endl;cout << "num1 = " << num1 << endl;cout << "num2 = " << num2 << endl;int temp = num1;num1 = num2;num2 = temp;cout << endl;cout << "交换后:" << endl;cout << "num1 = " << num1 << endl;cout << "num2 = " << num2 << endl;//return ; // 当函数声明时候,不需要返回值,可以不写return
}int main() {int a = 10;int b = 20;cout << "mian中的 a = " << a << endl; // 10cout << "mian中的 b = " << b << endl; // 20swap(a, b); // 当我们做值传递的时候,函数的形参发生改变,并不会影响实参cout << endl;cout << "mian中的 a = " << a << endl; // 10cout << "mian中的 b = " << b << endl; // 20cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

1.5 函数常见样式
常见的函数样式有4种:
(1)、无参无返
(2)、有参无返
(3)、无参有返
(4)、有参有返
// 函数常见样式#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间// 1、无参无返
void test01()
{//void a = 10; //无类型不可以创建变量,原因无法分配内存cout << "this is test01" << endl;//test01(); 函数调用
}// 2、有参无返
void test02(int a)
{cout << "this is test02" << endl;cout << "a = " << a << endl;
}// 3、无参有返
int test03()
{cout << "this is test03 " << endl;return 10;
}// 4、有参有返
int test04(int a, int b)
{cout << "this is test04 " << endl;int sum = a + b;return sum;
}int main() {test01();cout << endl;test02(10);cout << endl;cout << test03() << endl;cout << endl;cout << test04(20, 30) << endl;cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

1.6 函数声明
作用: 告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义
函数的声明可以多次,但是函数的定义只能有一次
// 函数常见样式#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间// 声明
int max(int a, int b); // 提前告诉编译器函数的存在,可以利用函数的声明;声明后,函数的定义可以写在main函数之后// 定义
int max(int a, int b)
{return a > b ? a : b; // 比较函数,实现两个整型数字进行比较,返回较大的值
}int main() {int a = 100;int b = 200;cout << max(a, b) << endl; // 调用函数cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

1.7 函数分文件编写
作用: 让代码结构更加清晰
函数分文件编写一般有4个步骤:
(1)、创建后缀名为.h的头文件
(2)、创建后缀名为.cpp的源文件
(3)、在头文件中写函数的声明
(4)、在源文件中写函数的定义
swap.h
#include <iostream> // 包含输入输出流;不写引用cout时会提示:未定义
using namespace std; // 框架;命名空间;域// 实现两个数字交换的函数声明
void swap(int a, int b);
swap.cpp
#include "swap.h" // ""代表自定义的头文件void swap(int a, int b)
{int temp = a;a = b;b = temp;cout << "a = " << a << endl;cout << "b = " << b << endl;
}
main.cpp
#include <iostream>
using namespace std;#include "swap.h"int main() {int a = 100;int b = 200;swap(a, b);cout << endl;system("pause");return 0;
}

1.8 函数默认参数
在 C++ 中,函数的形参列表中的形参是可以有默认值的
语法: 返回值类型 函数名 (参数= 默认值){}
#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间// 如果我们自己传入数据,就用自己的数据,如果没有,那么用默认值
// 语法:返回值类型 函数名 (形参 = 默认值) {}
int func(int a, int b = 10, int c = 10) {return a + b + c;
}// 注意事项:
// 1. 如果某个位置参数有默认值,那么从这个位置往后,从左向右,必须都要有默认值
// 2. 如果函数声明有默认值,函数实现的时候就不能有默认参数
int func2(int a = 10, int b = 10);
int func2(int a, int b) { // 二义性;如果定义func2中给形参a,b默认值,调试程序时会报错;声明和实现只能有一个默认参数return a + b;
}int main() {cout << "ret = " << func(20, 20) << endl; // 50cout << "ret = " << func(100) << endl; // 120cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

1.9 函数占位参数
C++ 中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置
语法: 返回值类型 函数名 (数据类型){}
#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间// 语法:返回值类型 函数名 (数据类型) {}
// 函数占位参数 ,占位参数也可以有默认参数 ; {int a, int = 10}
void func(int a, int) {cout << "this is func" << endl;
}int main() {func(10, 10); // 占位参数必须填补cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

1.9 函数重载
1.9.1 函数重载概述
作用: 函数名可以相同,提高复用性
函数重载满足条件:
(1)、同一个作用域下
(2)、函数名称相同
(3)、函数参数类型不同 或者 个数不同 或者 顺序不同
注意: 函数的返回值不可以作为函数重载的条件
// 函数重载:可以让函数名相同,提高复用性#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间// 函数重载的满足条件
// 1、函数重载需要函数都在同一个作用域下
// 2、函数名称相同
// 3、函数参数类型不同,或者个数不同,或者顺序不同
void func()
{cout << "func 的调用!" << endl;
}void func(int a)
{cout << "func (int a) 的调用!" << endl;
}void func(double a)
{cout << "func (double a)的调用!" << endl;
}void func(int a, double b)
{cout << "func (int a ,double b) 的调用!" << endl;
}void func(double a, int b)
{cout << "func (double a ,int b)的调用!" << endl;
}// 函数返回值不可以作为函数重载条件
//int func(double a, int b)
//{
// cout << "func (double a ,int b)的调用!" << endl;
//}int main() {func();func(10);func(3.14);func(10, 3.14);func(3.14, 10);cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

1.9.2 函数重载注意事项
(1)、引用作为重载条件
(2)、函数重载碰到函数默认参数
// 函数重载注意事项#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间// 1、引用作为重载条件
void func(int& a)
{// int &a = 10;不合法;引用必须要有合法的内存空间(堆区、栈区);10在常量区cout << "func (int &a) 调用 " << endl;
}void func(const int& a) // 函数重载;int和const int类型不同;const int &a = 10;合法;const会做优化,创建一个临时的数据,&a指向临时的内存空间
{cout << "func (const int &a) 调用 " << endl;
}// 2、函数重载碰到函数默认参数
void func2(int a, int b = 10)
{cout << "func2(int a, int b = 10) 调用" << endl;
}void func2(int a)
{cout << "func2(int a) 调用" << endl;
}int main() {int a = 10;func(a); // 调用无const(int &a);a是变量,可读可写;const只可读func(10); // 调用有const(const int &a) //func2(10); // 碰到默认参数产生歧义,需要避免;二义性cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

2 指针
2.1 指针基本概念
指针的作用: 可以通过指针间接访问内存
(1)、内存编号是从0开始记录的,一般用十六进制数字表示
(2)、可以利用指针变量保存地址
2.2 指针变量定义和使用
指针变量定义语法: 数据类型 * 变量名;
#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间int main() {// 1、指针的定义int a = 10; // 定义整型变量a// 指针定义语法: 数据类型 * 变量名 ;int* p;// 指针变量赋值p = &a; // 指针指向变量a的地址cout << &a << endl; // 打印数据a的地址 ; 00FFA5Ccout << p << endl; // 打印指针变量p ; 00FFA5C// 2、指针的使用// 通过*操作指针变量指向的内存cout << "*p = " << *p << endl; // 10 ; 通过解引用的方式来找到指针指向的内存中的数据cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

指针变量和普通变量的区别:
(1)、普通变量存放的是数据,指针变量存放的是地址
(2)指针变量可以通过" * "操作符,操作指针变量指向的内存空间,这个过程称为解引用
2.3 指针所占内存空间
提问: 指针也是种数据类型,那么这种数据类型占用多少内存空间?
#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间int main() {int a = 10;int* p = &a; // 指针指向数据a的地址cout << *p << endl; // * 解引用 ; 10// 在32位操作系统下,指针是占4个字节空间大小,不管是什么数据类型// 在64位操作系统下,指针是占8个字节空间打下cout << sizeof(p) << endl; // 8cout << sizeof(char*) << endl; // 8cout << sizeof(float*) << endl; // 8cout << sizeof(double*) << endl; // 8cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

2.4 空指针和野指针
空指针: 指针变量指向内存中编号为0的空间
用途: 初始化指针变量
注意: 空指针指向的内存是不可以访问的
#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间int main() {// 指针变量p指向内存地址编号为0的空间int* p = NULL;// 访问空指针报错 // 内存编号0 ~255为系统占用内存,不允许用户访问cout << *p << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}
野指针: 指针变量指向非法的内存空间
#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间int main() {// 指针变量p指向内存地址编号为0x1100的空间int* p = (int*)0x1100; // 0x1100十六进制;(int *)强转为指针类型;没有权利操作编号为0x1100的内存空间// 访问野指针报错 cout << *p << endl; // 引发异常:读取访问权限冲突system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}
2.5 const 修饰指针
const 修饰指针有三种情况:
(1)、const 修饰指针 — 常量指针

(2)、const 修饰常量 — 指针常量

(3)、const 即修饰指针,又修饰常量

#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间int main() {int a = 10;int b = 10;// 1、常量指针// const 修饰的是指针,指针指向可以改,指针指向的值不可以更改const int* p1 = &a;p1 = &b; // 正确// *p1 = 100; 报错// 2、指针常量// const 修饰的是常量,指针指向不可以改,指针指向的值可以更改int* const p2 = &a;//p2 = &b; // 错误*p2 = 100; // 正确// 3、const 既修饰指针又修饰常量const int* const p3 = &a;// p3 = &b; // 错误// *p3 = 100; // 错误system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}
2.6 指针和数组
作用: 利用指针访问数组中元素
#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间int main() {int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int* p = arr; // 指向数组的指针;arr就是数组首地址cout << "第一个元素: " << arr[0] << endl; // 1cout << "指针访问第一个元素: " << *p << endl; // 1p++; // 让指针向后偏移4/8个字节(看不同操作系统)cout << "指针访问第二个元素: " << *p << endl; // 2cout << endl;p--;for (int i = 0; i < 10; i++){//利用指针遍历数组cout << *p << endl;p++;}cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

2.7 指针和函数
作用: 利用指针作函数参数,可以修改实参的值
#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间// 值传递
void swap1(int a, int b)
{int temp = a;a = b;b = temp;
}// 地址传递
void swap2(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}int main() {int a = 10;int b = 20;swap1(a, b); // 值传递不会改变实参swap2(&a, &b); // 地址传递会改变实参cout << "a = " << a << endl; // 20cout << "b = " << b << endl; // 10cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

2.8 指针、数组、函数
案例描述: 封装一个函数,利用冒泡排序,实现对整型数组的升序排序
例如数组:int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };
#include <iostream> // 包含标准输入输出流文件
using namespace std; // 使用标准命名空间// 冒泡排序函数
void bubbleSort(int* arr, int len) // int * arr 也可以写为int arr[];数组首地址;数组长度
{for (int i = 0; i < len - 1; i++){for (int j = 0; j < len - 1 - i; j++){if (arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}// 打印数组函数
void printArray(int arr[], int len)
{for (int i = 0; i < len; i++){cout << arr[i] << " ";}cout << endl;
}int main() {int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };int len = sizeof(arr) / sizeof(int); // 数组长度bubbleSort(arr, len);printArray(arr, len); // 1,2,3,4,5,6,7,8,9,10cout << endl;system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}

总结
(1)、函数定义里小括号内称为形参,函数调用时传入的参数称为实参;
(2)、值传递时,形参是修饰不了实参的;
(3)、我们可以通过 & 符号 获取变量的地址;
(4)、利用指针可以记录地址;
(5)、对指针变量解引用,可以操作指针指向的内存;
(6)、所有指针类型在32位操作系统下是4个字节;
(7)、空指针和野指针都不是我们申请的空间,因此不要访问;
(8)、技巧:看const右侧紧跟着的是指针还是常量,是指针就是常量指针,是常量就是指针常量;
(9)、如果不想修改实参,就用值传递,如果想修改实参,就用地址传递;
(10)、当数组名传入到函数作为参数时,被退化为指向首元素的指针。
相关文章:
【C++ 四】函数、指针
函数、指针 文章目录 函数、指针前言1 函数1.1 概述1.2 函数定义1.3 函数调用1.4 值传递1.5 函数常见样式1.6 函数声明1.7 函数分文件编写1.8 函数默认参数1.9 函数占位参数1.9 函数重载1.9.1 函数重载概述1.9.2 函数重载注意事项 2 指针2.1 指针基本概念2.2 指针变量定义和使用…...
虚拟人与娱乐传媒融合,推动综艺新模式
经过多年的更新迭代和市场的推动,虚拟人技术正在逐渐迈向成熟:3D虚拟形象的制作变得越来越精致且真实,并且出现了越来越多功能丰富使用便捷的动捕设备。因此,包括综艺影视在内的诸多领域,开始尝试将虚拟人技术融入行业…...
Linux_红帽8学习笔记分享_5
Linux_红帽8学习笔记分享_5 文章目录 Linux_红帽8学习笔记分享_51. UMASK反掩码1.1如何查看反掩码umask1.2 UMASK反掩码的作用1.2.1对于目录来说1.2.2对于文件来说 1.3如何修改UMASK反掩码1.4普通用户反掩码的测试 2.whereis的使用3. SUID权限弥补(主要针对文件,所有者执行位变…...
网络编程及项目思路
计算机和计算机之间通过网络进行数据传输 常见的软件架构: C/S:客户端/服务器 画面可以做的非常精美,用户体验好需要开发客户端,也需要开发服务端用户需要下载和更新的时候太麻烦 B/S:浏览器/服务器 不需要开发客户端,只需要…...
GD(兆易创新)系列FLASH进行FPGA和ZYNQ配置固化相操作
写在前面 本文主要针对使用GD(兆易创新)系列的FLASH做启动配置片时,遇到的相关问题进行简单整理复盘,避免后人踩坑。 本人操作固化芯片型号为:ZYNQ7045、690T(复旦微替代型号V7 690T)。 7系列…...
通过一个小例子来看一下C语言指针 p、*p、p、*p、*p分别代表什么
前言 在C语言中,指针是非常重要的概念。指针是一个变量,其值为另一个变量的地址。使用指针可以直接访问内存中的数据,这使得C语言非常灵活和强大。在学习C语言时相比大家都已经知道了&和*的区别了,但是你知道*&p和&*…...
【内摹访谈】谈谈AI爆发前夜的B端设计
本文来自摹客产品设计团队(MPD)的设计专栏“内摹访谈”。专栏介绍:专栏名称来源于西方美学理论「内摹仿说」,意指审美活动与摹仿活动紧密相连,审美不只针对表象动作,其核心在于由物及我,从表观带…...
Redis—AOF持久化
一、AOF定义 保存写操作命令到日志的持久化方式,就是 Redis 里的 AOF(Append Only File) 持久化功能 定义:以日志的形式记录每个操作,记录写指令不记录读指令,只许追加⽂件不允许修改,AOF保存的是appendonly.aof⽂件…...
OpenCV实例(五)指纹识别
OpenCV实例(五)指纹识别 1.指纹识别概述1.1概述1.2原理 2.指纹识别算法2.1特征提取2.2MCC匹配方法2.3尺度不变特征变换(SIFT) 3.显示指纹的关键点4.基于SIFT的指纹识别 作者:Xiou 1.指纹识别概述 1.1概述 指纹识别&…...
第二章 法的内容与形式
目录 第一节 法的内容与形式的概念 一、法的内容与形式的含义 二、法的内容和形式的关系 第二节 法律权利与法律义务 一、权利和义务的概念 二、权利和义务的分类 三、权利与义务的联系 第三节 法的成文形式与不成文形式 一、历史上各种法的表现形式 二、成文法与不成文…...
外包干了四年,感觉废了..
先说一下自己的情况,大专生,18年通过校招进入湖南某软件公司,干了接近4年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…...
Git如何推送当前代码到远程仓库
第一种方法 (建立在已经配置好用户变量和ssh基础上) 在本地创建git仓库 git init 绑定远程仓库,origin是给远程仓库起的别名,也可以起其他名字,但是如果用origin,git push时可以不指出名字,如果…...
第五章 工厂模式
文章目录 一、简单工厂模式1、传统方式实现披萨订购( 可以忽略)披萨父类 Pizza子类胡椒披萨 PepperPizza子类印度披萨 GreekPizza订购披萨 OrderPizza订购披萨的 客户端 PizzaStore运行结果传统的方式的优缺点,新增子类需要修改的地方牵扯太多传统方式的究极耦合 2、…...
Spring MVC 参数解析(13)
目录 简介 调用流程 1. 首先,还是需要进行到前端控制器的doDispatch方法,这是我们的调用Spring MVC的核心入口方法 2. 在doDispatch方法内部,我们调用到了HandlerAdapter.handle(*****) 方法 3. 最终,我们会来到 RequestMappi…...
探索 Qt WebEngineWidgets:从底层原理到高级应用与技巧
探索 Qt WebEngineWidgets:从底层原理到高级应用与技巧 (Exploring Qt WebEngineWidgets: From Fundamentals to Advanced Applications and Techniques 一、Qt WebEngineWidgets 模块简介及原理 (Introduction and Principles of Qt WebEngineWidgets Module)1. Qt…...
leetcode160. 相交链表
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意,函数返回结果后&…...
核心业务7:放款实现
核心业务7:放款实现 1.放款实现流程 -------------------未完成生成借款人还款计划和投资人回款计划-------------- 2.数据库表 3.前端流程 4.汇付宝流程 5.尚融宝后端流程 -------------------未完成生成借款人还款计划和投资人回款计划-------------- -------------…...
STM32F4系列芯片RTC模块介绍
RTC是“实时时钟”的缩写,它是一种芯片,在计算机等电子产品中广泛应用。RTC提供了实时时钟计时功能和存储时间的能力,即时钟模块,常用于控制和记录时间的应用场合。 RTC的工作原理 RTC主要由时钟电路、电源管理电路、晶振电路、…...
MySQL 在线人数 场景分析
一般在直播或者游戏中经常会统计用户在线人数,主要分为求每个时刻的在线人数和求某个时刻的在线人数两种。 【场景】:某个时刻的在线人数、每个时刻的在线人数 【知识点】:窗口函数、时间函数、sum(tag) over (order by dt,tag desc rows b…...
使用mybatis和dynamic-datasource-spring-boot-starter动态切换数据源操作数据库
记录:415 场景:使用mybatis和dynamic-datasource-spring-boot-starter动态切换数据源操作数据库。 版本:JDK 1.8,Spring Boot 2.6.3,dynamic-datasource-spring-boot-starter-3.3.2,mybatis-3.5.9。 源码:https://github.com/b…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...
解析“道作为序位生成器”的核心原理
解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制,重点解析"道作为序位生成器"的核心原理与实现框架: 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...
归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...
结构化文件管理实战:实现目录自动创建与归类
手动操作容易因疲劳或疏忽导致命名错误、路径混乱等问题,进而引发后续程序异常。使用工具进行标准化操作,能有效降低出错概率。 需要快速整理大量文件的技术用户而言,这款工具提供了一种轻便高效的解决方案。程序体积仅有 156KB,…...
