C++基础从0到1入门编程(二)
系统学习C++
方便自己日后复习,错误的地方希望积极指正
往期文章:C++基础从0到1入门编程(一)
参考视频:
1.黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难
2.系统化学习C++
1 函数指针和回调函数
如果把函数的地址作为参数传递给函数,就可以在函数中灵活的调用其他函数
三步走:
(1)声名函数指针
int fun(int a, string b);
//函数指针的声明
int (*pfun)(int, string);
(2)让函数指针指向函数的地址
pfun = fun;
(3)通过函数指针调用函数
(*pfun)(2,"asd"); // C
pfun(2,"asd"); // C++
#include <iostream>
#include <string>
using namespace std;void func(int no, string str)
{cout << no << ' ' << str;
}
int main()
{int bh = 3;string message = "i'm a dog";func(bh, message);// 声明函数指针void (*pfunc)(int, string);// 对函数指针赋值,函数指针名 = 函数名pfunc = func;// 用函数指针名调用函数 C++pfunc(bh, message);// 用函数指针名调用函数 C语言(*pfunc)(bh, message);return 0;
}
函数指针的使用场景(回调函数):
开了一个皮包公司,专门承接表白业务
表白之前的准备工作和表白之后的收尾工作,公司都帮你做好,向女生表白这件事由你自己来做,别人是帮不了的。
用函数指针回调函数和用函数名调用函数意义不一样
回调函数:把一个函数的代码嵌入到另一个函数中,调用者函数提供了主体的流程和框架,具体的功能由回调函数来实现。写调用者函数的时候,只确定回调函数的种类,不关心回调函数的功能。
函数名调用函数:调用函数时,知道函数名和功能
#include <iostream>
using namespace std;void BigDavid(int a)
{cout << a << "Hello World" << endl;
}void Hw(int a)
{cout << a << "asd\n";
}
//void show(void (*pf)())
//{
// cout << "front" << endl;
// pf();
// cout << "done" << endl;
//}void show(void (*pf)(int), int b)
{cout << "front" << endl;pf(b);cout << "done" << endl;
}int main()
{show(BigDavid, 3);show(Hw, 4);
}
2 补充一些数组的概念
2.1 清空数组和复制数组
(1)清空数组
用memset()函数可以把数组中全部元素清零(适用于C++基本数据类型)
void *memset(void *s, int c, size_t n);
在Linux下,使用memcpy()函数要加头文件#include <cstring>
(2)复制数组
用memcpy()函数可以将数组中全部的元素复制到另一个相同大小的数组
void *memcpy(void *dest, const void *src, size_t n);
第一个参数:目标数组名
第二个参数:原数组名
第三个参数:整个数组占用内存空间的大小
#include <iostream>
#include <cstring>
using namespace std;int main()
{int bh[] = {1, 2, 4, 6};string name[3];for (int i = 0; i < 4; i++){cout << i << ' ' << bh[i] << endl;}memset(bh,0,sizeof(bh));for (int i = 0; i < 4; i++){cout << i << ' ' << bh[i] << endl;}int bh1[sizeof(bh) / sizeof(int)];memcpy(bh1, bh, sizeof(bh));for (int i = 0; i < 4; i++){cout << i << ' ' << bh1[i] << endl;}}
2.2 一维数组用于函数的参数
1.指针的数组表示
数组名[下标] = *(数组首地址 + 下标)
地址[下标] = *(地址 + 下标)
#include <iostream>
using namespace std;int main()
{char a[20];int* p = (int *)a;for (int i = 0; i < 5; i++){p[i] = i + 300;}for (int i = 0; i < 5; i++){cout << *(p + i) << endl;}
}
2.一维数组用于函数的参数
void fun(int* arr, int len);
void fun(int arr[], int len);
#include <iostream>
using namespace std;void func(int arr[], int len)
{for (int i = 0; i < len; i++){cout << arr[i] << endl;}
}
int main()
{int a[] = {1, 2, 4, 5};func(a, 4);
}
2.3 用new动态创建一维数组
数据类型 *指针 = new 数据类型[数组长度];
释放一维数组的语法:delete[] 指针;
#include <iostream>
using namespace std;int main()
{int* arr = new int[8];for (int i = 0; i < 8; i++){arr[i] = 100 + i;cout << *(arr + i) << endl;}delete[] arr;return 0;
}
Tip:
(1)动态创建的数组没有数组名,不能用sizeof运算符
(2)可以用数组表示法和指针表示法使用动态创建的数组
(3)必须使用delete[]释放内存
(4)不要用delete[]释放不是new[]分配的内存
(5)不用delete[]释放同一个内存块两次(否则相同于操作野指针)
(6)对空指针用delete[]是安全的(释放内存后,应该把指针置空nullptr)
(7)声名普通数组,数组长度可以用变量,相当于在栈上动态创建数组,并且不需要手动释放
(8)非常重要:如果内存不足,调用new会产生异常,导致程序终止;如果在new关键字后面加(std::nothrow)选项,则返回nullptr,不会产生异常
#include <iostream>
using namespace std;int main()
{int *a = new (std::nothrow) int[10000000001];if (a == nullptr){cout << "failed" << endl;}else{a[10000000000] = 8;delete[] a;}return 0;
}
(9)为什么用delete[]释放数组的时候,不需要指定数组的大小?因为系统会自动跟踪已分配数组的内存
2.4 数组最经典的两种应用场景:排序和查找
(1)数组的排序qsort
qsort()函数用于对各种数据类型的数组进行排序
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void*, const void *))
第一个参数:数组的起始地址
第二个参数:数组元素的个数
第三个参数:数组元素的大小(sizeof(数组的数据类型))
第四个参数:回调函数的地址
回调函数决定了排序的顺序
int compar(const void* p1, const void* p2);
1)如果函数的返回值< 0 ,那么p1所指向元素会被排在p2所指向元素的前面。
2)如果函数的返回值==0,那么p1所指向元素与p2所指向元素的顺序不确定。
3)如果函数的返回值> 0 ,那么p1所指向元素会被排在p2所指向元素的后面。
qsort()函数细节
(1)形参中的地址用void是为了支持任意数据类型,在回调函数中必须具体化。
(2)排序的需求除了升序和降序,还有很多不可预知的情况,只能用回调函数
#include <iostream>
using namespace std;
// 从小到大排序
int compasc(const void* p1, const void* p2) // 升序的回调函数
{
// if (*(int*)p1 < *(int*)p2) return -1;
// if (*(int*)p1 == *(int*)p2) return 0;
// if (*(int*)p1 > *(int*)p2) return 1;return *(int*)p1 - *(int*)p2;
}
int compdesc(const void* p1, const void* p2) // 降序的回调函数
{return *(int*)p2 - *(int*)p1;
}
int main()
{int a[8] = { 2,1,7,8,4,0, 11, 9};for (int i = 0; i < 8; i++){cout << a[i] << ' ';}cout << endl;qsort(a,sizeof(a)/sizeof(a[0]),sizeof(a[0]),compdesc);for (int i = 0; i < 8; i++){cout << a[i] << ' ';}return 0;
}
(2)数组的查找
二分法详见:数组之二分查找
2.5 C风格字符串
C++用的是string,能自动扩展,不考虑内存和野指针问题
string是C++的类,封装了C风格的字符串
在某些场景,C风格字符串更方便、高效
C语言约定:如果字符型(char)数组的末尾包含了空字符\0(也就是0),那么该数组中的内容就是一个字符串
#include <iostream>
using namespace std;
int main()
{string x = "XY";cout << x[0] << x[1] << x[2];
}
一些操作
(1)初始化
char name[11];
char name[11] = { "hello" };
char name[] = { "sd" };
char name[11] { "hello" };
char name[11] = { 0 }; //把全部元素初始化为0
(2)清空字符串
memset(name, 0, sizeof(name));
name[0] = 0; //不推荐
(3)字符串复制strcpy()
复制完字符串后,会在dest后追加0
如果参数dest所指的内存空间不够大,会导致数组的越界
strcpy(name1, name);
将参数name字符串拷贝至参数name1所指的地址
(4)字符串赋值strncpy
strncpy(name1, name, 3);
把name前3个字符的内容复制到name1中
如果src字符串长度小于n,则拷贝完字符串后,在dest后追加0,直到n个。
如果src的长度大于等于n,就截取src的前n个字符,不会在dest后追加0。
如果参数dest所指的内存空间不够大,会导致数组的越界。
(5)获取字符串的长度strlen()
(6)字符串拼接strcat()
(7)字符串拼接strncat()
(8)字符串比较strcmp()和strncmp()
相等返回0,str1大于str2返回1,str1小于str2返回-1
strcmp(str1, str2);
strcmp(str1, str2, 3);
(9)查找strchr()和strchr()
const char *strchr(const char *s, int c);
返回在字符串s中第一次出现c的位置,如果找不到,返回0。
const char *strrchr(const char *s, int c);
返回在字符串s中最后一次出现c的位置,如果找不到,返回0。
(10)查找字符串strstr()
char * strstr(const char* str,const char* substr);
功能:检索子串在字符串中首次出现的位置。
返回值:返回字符串str中第一次出现子串substr的地址;如果没有检索到子串,则返回0。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
int main()
{// 初始化方法char name[11]; // 存放了10个字符,没有初始化,里面都是垃圾值char name1[11] = "hello";char name2[] = { "asd" }; //4char name3[11] = { "asd" };char name4[11] {"asd"}; // C++11标准char name5[11] = {0};for (int i = 0; i < 11; i++){cout << name1[i] << endl;}// 清空字符串memset(name1, 0, sizeof(name));// 字符串复制或赋值strcpy()strcpy(name, name3);// 字符串赋值或赋值strncpy()strncpy(name, "hello", 8);// 获取字符串的长度strlen()cout << strlen(name) << endl;// 字符串拼接strcat()cout << strcat(name, name3) << endl;// 字符串拼接strncat()cout << strncat(name, name3, 2) << endl;// 字符串比较strcmp()和strncmp()cout << strcmp(name1, name2) << endl;cout << strncmp(name1, name2, 2) << endl;// 字符查找strchr()和strtchr()cout << strchr(name1, 0) << endl;// 字符串查找strstr()cout << strstr(name1, name2) << endl;
}
(11)Tip
1.结尾标志0后面都是垃圾内容
2.字符串每次使用前都要初始化
3.不要在子函数中对字符指针用sizeof运算,所以,不能在子函数中对传入的字符串进行初始化,除非字符串的长度也作为参数传入到了子函数中。
2.6 二维数组一些补充
其他一些基本概念在C++基础从0到1入门编程(一)
(1)清空二维数组
用memset()函数把二维数组中全部的元素清零
(2)复制二维数组memcpy()
(3)二维数组用于函数的参数
复习之前学过的指针
int* p; // 整型指针
int* p[3]; // 一维整型指针数组
int* p(); // 函数p的返回值类型是整型的地址
int (*p)(int, int);// p是函数指针,函数的返回值是整型
行指针
数据类型 (*行指针名)[行的大小];
int (*p1)[3]; // p1是行指针,用于指向数组长度为3的int型数组
二维数组名是行地址
int bh[2][3] = { {1, 2, 3}, {2, 1, 4} };
bh是二维数组名,该数组有两元素,每一个元素本身又是一个数组长度为3的整型数组。
bh:数组长度为3的整型数组类型的行地址
如果存放bh的值,要用数组长度为3的整型数组类型的行指针
int bh[2][3] = { {1, 2, 3}, {2, 1, 4} };
int (*p)[3] = bh;int bh[4][2][3];
int (*p)[2][3] = bh;
把二维数组传递给函数
void fun(int (*p)[3], int len);
void fun(int p[][3], int len);
实操:
#include <iostream>
#include <cstring>
using namespace std;//void fun(int p[][3], int len)
//{
// for (int i = 0; i < len; i++)
// {
// for (int j = 0; j < 3; j++)
// {
// cout << p[i][j] << " ";
// }
// cout << endl;
// }
//}
void fun(int (*p)[2][3])
{int i = 0;for (int a = 0; a < 4; a++){for (int b = 0; b < 2; b++){for (int c = 0; c < 3; c++){p[a][b][c] = i++;}}}
}
int main()
{int a[10];cout << a + 1<< endl; // +4cout << &a + 1<< endl; // +40// int bh[2][3] = { {1, 2, 3}, {2, 1, 4} };// fun(bh, 2);int bh[4][2][3];memset(bh, 0, sizeof(bh));fun(bh);for (int a = 0; a < 4; a++){for (int b = 0; b < 2; b++){for (int c = 0; c < 3; c++)cout << bh[a][b][c] << '\t';cout << endl;}cout << endl << endl;}
}
3 结构体基本概念
3.1 定义结构体
结构体:将多种数据整合到一起,描述一个完整的对象
Tip:
(1)结构体成员可以用C++的类(string),但是不提倡
(2)C++中,结构体可以有函数,不推荐
(3)C++中,定义结构体可以指定缺省值
3.2 创建结构体变量
struct 结构体名 结构体变量名;
struct 结构体名 结构体变量名={成员一的值, 成员二的值,…, 成员n的值}
如果大括号内未包含任何东西或只写一个0,全部的成员都将被设置为0
Tip: C++中,struct关键字可以不写;可以在定义结构体的时候创建结构体变量
3.3 使用结构体
结构体变量名.结构体成员名;
3.4 占用内存的大小
使用sizeof运算符可以得到整个结构体占用内存的大小
整个结构体占用内存的大小不一定等于全部成员占用内存之和
3.5 清空结构体
用memset()函数可以把结构体中全部的成员清零。
bzero()函数也可以。
3.6 复制结构体
使用memcpy()函数把结构体中的全部元素复制到另一个相同类型的结构体,也可以直接用=
实操:
#include <iostream>
#include <cstring>
using namespace std;
#pragma pack(8)struct girl
{char name[20];int age;double weight;char sex;bool yanzhi;
};int main()
{girl girl{"DiaoChan", 26, 99.9, 'X', true};cout << sizeof(girl) << endl;memset(&girl, 0, sizeof(girl));cout << girl.name << ' ' << girl.age << ' ' << girl.weight << ' ' << girl.sex << ' ' << girl.yanzhi << endl;return 0;
}
4 结构体指针
C++中,用不同类型的指针存放不同类型变量的地址,这一规则也适用于结构体
4.1 语法
struct Girl girl;
struct Girl *pst = &girl; // 声明结构体指针,指向结构体变量
通过结构体指针访问结构体成员
(*指针名).成员变量名
指针名->成员变量名 // 通常用这个,直观
4.2 用于函数的参数
如果把结构体传递给函数,实参取结构体变量的地址,函数的形参用结构体指针
如果不希望在函数中修改结构体变量的值,可以对形参加const约束
4.3 用结构体指针指向动态分配的内存的地址
结构体指针指向动态分配的内存的地址
#define _CRT_SECURE_NO_WARNINGS // 如果要使用C标准库的字符串函数,需要加上这一行代码
#include <iostream>
#include <cstring>
using namespace std;struct Girl
{char name[20];int age;double weight;char sex;bool yanzhi;
};void fun(const Girl* pst)
{cout << pst->name << ' ' << pst->age << ' ' << pst->sex << ' ' << pst->weight << ' ' << pst->yanzhi;
}
int main()
{Girl* girl = new Girl({"DiaoChan", 26, 99.9, 'X', true});fun(girl);delete girl;return 0;
}
5 结构体数组
struct 结构体类型 数组名[数组长度];
#define _CRT_SECURE_NO_WARNINGS // 如果要使用C标准库的字符串函数,需要加上这一行代码
#include <iostream>
#include <cstring>
using namespace std;struct Girl
{char name[20];int age;double weight;char sex;bool yanzhi;
};int main()
{Girl girls[3];memset(girls, 0, sizeof(girls));girls[1] = {"xigua",2,10.2,'X',false};strcpy(girls[0].name, "asd");girls[0].age = 11; (girls + 0)->yanzhi = true;for (int i = 0; i < 3; i++){cout << (girls + i)->name << ' ' << girls[i].age << endl;}return 0;
}
6 结构体嵌入数组和结构体
多维数组用于函数的参数
做法:把二维或者多维数组放在结构体中,作为结构体的一个成员,调用函数的时候,把结构体的地址传给函数,函数的形参接受结构体的地址,这样就可以绕过二维和多维数据传指针的问题。
#include <iostream>
using namespace std;struct st_girl
{char name[21];int score[2][3] = {1,3,4,2,2,1};int age;double weight;char sex;bool yz;
};void fun(st_girl* pst)
{for (int a = 0; a < 2; a++){for (int b = 0; b < 3; b++){cout << pst->score[a][b] << ' ';}cout << endl;}
}
int main()
{st_girl girl;fun(&girl);
}
结构体嵌入结构体
#include <iostream>
using namespace std;struct st_pet
{char name[21];char type[21];
};struct st_girl
{char name[21];int age;double weight;char sex;bool yz;struct st_pet pet;
};int main()
{st_girl girl = {"bigDavid",23,50.5,'X',true,{"as","ass"}};cout << girl.name << ' ' << girl.pet.type << ' ' << girl.pet.name << endl;
}
7 结构体中的指针
如果结构体的指针指向的是动态分配的内存地址:
(1)对结构体用sizeof没有意义
(2)对结构体用memset()函数可能会造成内存泄露(申请了堆区指针不释放)
在没有动态分配内存之前,是可以用memset()函数清空结构体
在没动态分配内存之后,逐个清空
#include <iostream>
#include <cstring>
using namespace std;struct st_t
{int a;int* p;
};int main()
{st_t stt;// memset(&stt, 0, sizeof(st_t));stt.a = 3;stt.p = new int[100];cout << sizeof(stt) << endl; // 16cout << stt.a << ' ' << stt.p << endl;// 清空成员astt.a = 0;// 清空成员p指向的内存中的内容memset(stt.p, 0, 100*sizeof(int));cout << stt.a << ' ' << stt.p << endl;delete[] stt.p;
}
(3)C++中的string中有一个指向的是动态分配的内存地址指针
struct string
{char *ptr;
};
memset一个带有指针成员类型是未定义的行为,不同编译器处理不一样,行为未定义结果肯定也未定义。string是c++封装的一个带有指针成员的类
string类的构造函数在构造string对象时,str_data指针会指向堆中字符串长度加1大小的内存空间,而使用memset函数对string类型对象清零后str_data变成了0,指向原内存空间在析构函数中不会被释放,导致内存泄漏。
不要轻易0初始化string、vector等STL标准容器及具有动态内存管理的类
#include <iostream>
#include <cstring>
using namespace std;
struct st_girl
{string name;
};
int main()
{st_girl girl;girl.name = "BigDavid";cout << girl.name << endl;//memset(&girl, 0, sizeof(girl));girl.name = "Liu";cout << girl.name << endl;
}
相关文章:
C++基础从0到1入门编程(二)
系统学习C 方便自己日后复习,错误的地方希望积极指正 往期文章:C基础从0到1入门编程(一) 参考视频: 1.黑马程序员匠心之作|C教程从0到1入门编程,学习编程不再难 2.系统化学习C 1 函数指针和回调函数 如果把函数的地址…...
Uniapp扫码预览连接地址与手机不在同一网段
在开发Uniapp应用时,这里有一个扫码预览的功能,电脑与手机都是在一网络下,之前点开后预览地址一直是169.254.3.x的地址,通过WINR键输入cmd运行,然后ipconfig查看所有网络连接。发现有一个虚拟网络连接的地址是169.251.…...
万界星空科技SMT行业生产管理MES系统解决方案
一、SMT行业特点: SMT(Surface Mounted Technology)作为电子组装行业里首先的技术和工艺,选择合适的MES解决方案来保障SMT生产的成功至关重要。 电子行业涉及的范围非常广,包含了汽车、电脑、电视、手机等产品上&…...
vue3 uniapp h5 安卓和iOS开发适配踩坑记录
font-size适配屏幕大小及iOS和安卓状态栏及安全距离的处理 App.vue <script setup lang"ts"> import { onLaunch, onShow, onHide } from "dcloudio/uni-app"; import ./main.scss onLaunch(() > {console.log("App Launch");var wid…...
inf和nan
在某些编程语法中inf表示无穷大,nan表示不是一个数(not a number) nan表示这个数不确定,而无穷大表示这个数任意大 1/0inf 这里把0当做一个无限接近0,但是非0的数 5-inf-inf 一个数减去无穷大会等于负无穷大 而inf-infnan 因为两个无穷大相减有很多可能,可能等于一个常数,也可能…...
十. Linux关机重启命令与Vim编辑的使用
关机重启命令 shutdown命令 其他关机命令 其他重启命令 系统运行级别 系统默认运行级别与查询 退出登录命令logout 文本编辑器Vim Vim简介 没有菜单,只有命令Vim工作模式 Vim常用命令 插入命令 定位命令 删除命令 复制和剪切命令 替换和取消命令 搜索和搜索替换命令 保存和退出…...
Spring-IOC-@Value和@PropertySource用法
1、Book.java PropertySource(value"classpath:配置文件地址") 替代 <context:property-placeholder location"配置文件地址"/> Value("${book.bid}") Value("${book.bname}") Value("${book.price}") <bean id&…...
如何理解Python中一切皆对象?
Python 一、示例代码二、Python中的魔法方法 一、示例代码 有理数类 import mathclass rational:def __init__(self,p,q):self.p pself.q qdef __str__(self):return "{} / {}".format(self.p,self.q)def simplify(self):gcd math.gcd(self.p,self.q)return rat…...
【如何学习Python自动化测试】—— 鼠标键盘操作
5 、 鼠标键盘操作 在浏览器中,通常会用到鼠标来进行操作,比如右键菜单中选择一个操作,在 selenium 中提供了下列鼠标相关操作。 ActionChains 类提供了以下方法: 点击鼠标:click()右击鼠标:context…...
随笔-事儿就这么个事儿
好久没写了,小A要催更,还答应让我写一下他的经历,这还有啥说的,开整。 1、升级 前段时间登录公司的办公系统处理一个事务申请,发现有个粗体标红的通知,是关于今年的晋升名单公示。进去看了一眼࿰…...
django理解03 数据库引入
配置 settings.py DATABASES {"default": {"ENGINE": "django.db.backends.mysql",NAME:307_django_db,USER: root,PASSWORD: 123456,HOST: 127.0.0.1,PORT: 3306,} }先创建指定名称的数据库databases create database self_django_db DEFAUL…...
Jtti:windows中apache怎么实现负载均衡
Jtti:windows中apache怎么实现负载均衡 在Windows环境下,你可以使用Apache HTTP Server搭建负载均衡集群。Apache提供了一个模块叫做mod_proxy,它可以用来实现反向代理和负载均衡。以下是一个简单的步骤来配置Apache负载均衡: 步骤…...
2311rust,到43版本更新
1.38.0 流水编译 要编译仓库,编译器不需要完全构建依赖项.相反,只需要它们的"元数据"(即类型,依赖关系,导出列表). 在编译过程的早期生成此元数据.从Rust1.38.0开始,Cargo利用这一点,在准备好元数据后立即自动开始构建依赖的仓库. 检查错误使用mem::{uninitialize…...
前端埋点上报的几种方式
现代Web应用程序中,埋点上报是一种重要的数据收集和分析手段。本文将介绍前端埋点上报的几种常见方式,并详细阐述如何在项目中运用这些方式进行数据上报,以帮助开发者更好地进行数据收集和分析。 上报方式 在前端中,常见的埋点上…...
外部 prometheus监控k8s集群资源
prometheus监控k8s集群资源 一,通过CADvisior 监控pod的资源状态1.1 授权外边用户可以访问prometheus接口。1.2 获取token保存1.3 配置prometheus.yml 启动并查看状态1.4 Grafana 导入仪表盘 二,通过kube-state-metrics 监控k8s资源状态2.1 部署 kube-st…...
centos安装神通数据库
1、安装 wget工具 yum install -y wget2、安装rar解压工具 wget --no-check-certificate http://www.rarlab.com/rar/rarlinux-x64-5.3.0.tar.gz tar zxvf rarlinux-x64-5.3.0.tar.gz && cd rar/ && make install3、下载oscar神通数据库(linux 64…...
汇编-PUSHFD和POPFD标志寄存器值压栈和出栈
PUSHFD指令将32位EFLAGS寄存器内容压入堆栈, 而POPFD指令则将栈顶单元内容弹出到EFLAGS寄存器 格式:...
基于SSM的进销存管理系统设计与实现
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用JSP技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…...
Django DRF限流组件
在DRF中,限流发生在认证、权限之后,限流组件的使用步骤: 1、编写自定义限流类; 2、在settings.py中配置redis; 3、安装django-redis; 4、启动redis服务; 5、局部应用,一般是在核心的视图中使用&…...
UEC++ day7
敌人NPC机制 敌人机制分析与需求 新建一个character类来作为敌人,直接建蓝图设置骨骼网格,因为敌人可能多种就不规定死,然后这个敌人肯定需要两个触发器,一个用于大范围巡逻,一个用于是否达到主角近点进行攻击 注意我…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型
在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...
stm32进入Infinite_Loop原因(因为有系统中断函数未自定义实现)
这是系统中断服务程序的默认处理汇编函数,如果我们没有定义实现某个中断函数,那么当stm32产生了该中断时,就会默认跑这里来了,所以我们打开了什么中断,一定要记得实现对应的系统中断函数,否则会进来一直循环…...
基于微信小程序的作业管理系统源码数据库文档
作业管理系统 摘 要 随着社会的发展,社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景,运用软件工程原理和开发方法,它主要是采用java语言技术和微信小程序来完成对系统的…...
