C语言基础18
内容提要
-
构造类型
-
结构体
-
共用体/联合体
-
枚举
-
typedef
-
构造类型
数据类型
-
基本类型/基础类型
-
整型
-
短整型:short [int] -- 2字节
-
基本整型:int -- 4字节
-
长整型:long [int] -- 32位4字节/64位8字节
-
长长整型:long long [int] -- 8字节(大多数现代机器,旧机器可能超过8字节),C99新增
注意:以上类型又都分为signed(默认)和unsigned
-
-
浮点型
-
单精度:float -- 4字节
-
双精度:double -- 8字节
-
长双精度:long double -- C99新增
-
-
字符型:char -- 1字节
-
-
指针类型
-
数据类型*:
int* char* float*
等 -- 8字节 -
void*:通用类型指针(万能指针) -- 8字节
-
-
空值类型
-
void:无返回值,无形参(不能定义变量)
-
-
构造类型(自定义类型)
-
结构体类型:struct
-
共用体/联合体类型:union
-
枚举类型:enum
-
结构体
结构体的定义【定义类型】
-
定义:自定义数据类型的一种,关键字struct,结构体类型的变量可以存储多个不同数据类型的数据。
-
语法:
struct 结构体名 // 我们定义的数据类型的名字{数据类型1 成员名称1; // 结构体中的变量叫做成员数据类型2 成员名称2; .....};
注意:结构体中定义的变量,称之为成员变量(成员属性)
-
格式说明:
-
结构体名:合法的标识符,建议首字母大写(所谓的结构体名,就是自定义类型的类型名称)
-
数据类型n:C语言支持的所有类型(包括函数,函数在这里用函数指针表示)
-
成员名称n:合法的标识符,就是变量的命名标准
-
数据类型n成员名称n:类似于定义变量,定义了结构体中的成员
-
-
注意:
-
结构体在定义的时候,成员不能赋值,举例:
struct Cat{int age = 5; // 错误,结构体定义的时候,成员不能赋值double height; // 正确void (*run)(void); // 正确};
-
-
常见的定义格式:
-
方式1:常规定义(命名结构体,只定义数据类型) -- 推荐
struct Student{int num; // 学号char name[20]; // 姓名char sex; // 性别int age; // 年龄char address[100]; // 籍贯void (*info)(void); // 信息输出(函数指针)};
-
方式2:定义匿名结构体(常用于作为其他结构体的成员使用)
struct Dog{char *name; // 姓名int age; // 年龄// 匿名结构体struct{// 匿名结构体定义时不能省略成员int year; // 年int month;// 月int day; // 日} birthday; // 生日,匿名结构体作为其他结构体成员时,需添加成员名称,否则无法访问};
注意:定义匿名结构体的同时必须定义结构体成员,否则编译报错;结构体可以作为另一个结构体的成员
总结:
-
结构体可以定义在局部位置,也可以定义在全局位置(用的比较多,因为可以实现复用)
-
全局位置的结构体名和局部位置的结构体名可以相同,遵循就近原则(和变量的定义同理)
-
-
-
结构体类型的使用:
利用结构体类型定义变量、定义数组,也可以作为函数的返回值和参数;结构体类型的使用与基本数据类型的使用类似。
结构体变量的定义【定义变量】
-
三种形式定义结构体变量
结构体变量也称之为结构体实例
-
第1种:
①先定义结构体(定义数据类型)
②然后使用(使用数据类型定义变量)
举例:
// 定义结构体(定义数据类型)struct A{int a;char b;};// 定义结构体变量struct A x; // struct A就是数据类型,x就是变量名struct A y; // struct A就是数据类型,y就是变量名
-
第2种:
①在定义结构体的同时,定义结构体变量
语法:
struct 结构体名{数据类型1 数据成员1;...} 变量列表;
举例:
struct A{int a;char b;} x,y;
此时定义了一个结构体A,x和y是这个结构体类型的变量
-
第3种:(不推荐)
在定义匿名结构体的同时,定义结构体变量
struct {int a;char b;} x,y;struct{int a;char b;} z;
此时定义了一个没有名字的结构体(匿名结构体);x,y是这个结构体类型的变量
-
-
匿名结构体
-
优点:少写一个结构体名称
-
缺点:只能使用一次,定义结构体类型的同时必须定义变量
-
应用场景:
-
当结构体的类型只需要使用一次,并且定义类型的同时定义变量
-
作为其他结构体的成员使用
-
-
定义结构体的同时,定义结构体变量初始化
struct Cat {int age;char color[20]; } cat;
-
结构体成员部分初始化时,大括号{}不能省略
-
结构体成员,没有默认值,是随机值
-
-
-
案例
/*** 先定义结构体,再定义结构体变量*/ void fun1() {// 定义结构体struct A{int a;char b;};// 定义结构体变量/实例struct A x;struct A y; }/*** 定义结构体的同时,定义结构体变量*/ void fun2() {struct A{int a;char b;} x,y;struct A z; }/*** 定义匿名结构体的同时定义变量*/ void fun3() {struct{int a; // 结构体成员char b;} x,y;struct{int a;char b;} z; }int main(int argc, char *argv[]) {fun1();fun2();fun3();return 0; }
结构体变量的使用
-
结构体变量访问结构体成员
-
语法:
结构体变量名.成员名;
①可以通过访问给成员赋值(存数据)
②可以通过访问获取成员的值(取数据)
-
结构体变量未初始化,结构体的成员是随机值(和普通的变量、数组同理)
-
-
结构体变量在定义时,可以初始化
-
建议用大括号{}标明数据的范围
-
结构体成员初始化,可以部分初始化(和数组类似),部分初始化时一定要带大括号标明数据的范围
-
-
案例:
/* 定义全局的结构体 */ struct Dog {char *name; // 名字int age; // 年龄char sex; // M:公,W:母void (*eat)(void); // 吃狗粮 };void eat() {printf("狗狗在吃狗粮!\n"); }/*** 方式1:先定义,再初始化*/ void fun1() {// 定义结构体变量struct Dog dog;// 给结构体变量成员赋值dog.name = "旺财";dog.age = 5;dog.sex = 'M';dog.eat = eat; // 函数指针,eat指针指向eat函数// 访问结构体变量成员printf("%s,%d,%c\n",dog.name, dog.age, dog.sex);// 访问成员方法(函数)dog.eat(); }/*** 方式2:定义的同时初始化*/ void fun2() {// 定义结构体变量的同时,给变量成员初始化struct Dog dog = {"旺财",5,'M',eat};// 修改成员的值dog.name = "金宝";// 访问结构体变量成员printf("%s,%d,%c\n",dog.name, dog.age, dog.sex);// 访问成员方法(函数)dog.eat(); }int main(int argc, char* argv[]) {fun1();fun2();return 0; }
结构体数组的定义
-
什么时候需要结构体数组
比如:我们需要管理一个学生对象,只需要定义一个
struct Student yixin;
假如:我们需要管理一个班的学生对象,此时就需要定义一个结构体数组
struct Student stus[33];
-
四种形式定义结构体数组
-
第1种:结构体 → 结构体变量 → 结构体数组,举例:
// 定义一个学生结构体(定义数据类型) struct Student {char* name; // 姓名int age; // 年龄float scores[3]; // 三门课程的成绩 };// 定义结构体变量/实例 struct Student zhangsan = {"张三",21,{89,99,78}}; struct Student lisi = {"李四",22,{66,78,98}};// 定义结构体数组 struct Student stus[3] = {zhangsan,lisi};
-
第2种:结构体 → 结构体数组,举例:
// 定义一个学生结构体(定义数据类型) struct Student {char* name; // 姓名int age; // 年龄float scores[3]; // 三门课程的成绩 };// 定义结构体数组并初始化 struct Student stus[3] = { {"张三",21,{89,99,78}},{"李四",22,{66,78,98}} };
-
第3种:结构体、结构体数组一体化(含初始化),举例:
// 定义一个学生结构体(定义数据类型) struct Student {char* name; // 姓名int age; // 年龄float scores[3]; // 三门课程的成绩 } stus[3] = { {"张三",21,{89,99,78}},{"李四",22,{66,78,98}} };
-
第4种:结构体、结构体数组一体化(不含初始化),举例:
// 定义一个学生结构体(定义数据类型) struct Student {char* name; // 姓名int age; // 年龄float scores[3]; // 三门课程的成绩 } stus[3];// 赋值 stus[0].name = "张三"; stus[0].age = 21; stus[0].scores[0] = 89; stus[0].scores[1] = 99; stus[0].scores[2] = 78;stus[1].name = "李四"; stus[1].age = 22; stus[1].scores[0] = 66; stus[1].scores[1] = 78; stus[1].scores[2] = 98;
-
结构体数组的访问
语法:
结构体指针 -> 成员名
举例:
// 普通指针访问 (*p).成员名 // 结构体指针访问(结构体指针访问符:->) 等价于上面写法 p -> 成员名
案例:
/* 定义全局Student结构体 */ struct Student {int id;char *name;int age;float scores[3];void (*info)(char*,int); };/*** 定义一个函数,输出信息*/ void info(char* name,int age) {printf("大家好,我是%s,今年%d岁了!\n",name,age); }void func() {// 定义结构体实例并初始化struct Student stu1 = {1,"张三",21,{78,88,98},info};struct Student stu2 = {2,"李四",22,{90,98,78},info};// stu1.info = info;// stu2.info = info;// 定义结构体数组并初始化struct Student stus[] = {stu1,stu2};// 遍历数组// 计算lenint len = sizeof(stus)/sizeof(stus[0]);// 指针遍历// 定义一个指针,获取遍历的学生对象struct Student *p = stus;for(; p < stus + len; p++){printf("%d,%s,%d,%.2f,%.2f,%.2f\n",p->id,p->name,p->age,p->scores[0],p->scores[1],p->scores[2]);// 调用函数 p-> info 等价于 (*p).info();p -> info(p -> name, p -> age);}printf("\n"); }int main(int argc, char* argv[]) {func();return 0; }
注意:
当
->
和[]
共存的时候,它们的优先级关系:[]
>->
结构体类型
结构体数组
案例
-
需求:对候选人得票的统计程序。设有3个候选人,每次输入一个得票的候选人名字,要求最后输出各人得票的结果
-
代码:
#include <string.h>/*** 定义一个候选人结构体*/ struct Person {char name[20]; // 候选人名字int count; // 候选人票数 };/*** 定义候选人数组,并初始化*/ struct Person persons[3] = {{"诸葛蛋蛋",0},{"司马苟丹",0},{"上官铁祝",0}, };int main(int argc, char *argv[]) {// 定义循环变量int i,j;// 创建一个char数组,用来接收控制台输入的候选人的名字char leader_name[20];// 使用一个for循环,模拟10次投票for(i = 0; i < 10; i++){printf("请输入您要投票的候选人姓名:\n");scanf("%s",leader_name);// 给被投票的候选人+1票for(j = 0; j < 3; j++){// 判断两个字符串的结果是否相同if(strcmp(leader_name,persons[j].name) == 0){persons[j].count++;}}}printf("\n投票结果:\n");// 方式1struct Person *p = persons; // p就是结构体指针for(; p < persons + 3; p++){// printf(" %s:%d\n",(*p).name, (*p).count);printf(" %s:%d\n",p -> name, p -> count);}printf("\n");// 方式2for(i = 0; i < 3; i++){printf(" %s:%d\n",(persons+i) -> name, (persons+i) -> count);}return 0; }
结构体指针
-
定义:结构体类型的指针变量指向结构体变量或者数组的起始地址
-
语法:
struct 结构体名 *指针变量列表;
-
举例:
struct Dog {char name[20];int age; };struct Dog dog = {"苟富贵",5};// 基于结构体的构造体指针 struct Dog *p = &dog;
结构体成员的访问
-
结构体成员访问
-
结构体数组名访问结构体成员
-
语法:
结构体数组名 -> 成员名; // 等价于如下写法 (*结构体数组名).成员名;
-
举例:
printf("%s:%d\n",persons -> name, persons -> count);
-
-
结构体成员访问符
-
.
:左侧是结构体变量,也可以叫做结构体对象访问成员符,右侧是结构体成员 -
->
:左侧是结构体指针,也可以叫做结构体指针访问成员符,右侧是结构体成员 -
举例:
struct Person *p = persons; // p 就是构造体指针 for(; p < persons + 3; p++)printf("%s:%d\n",p -> name, p -> count);
-
-
访问结构体成员有两种类型,三种方式:
-
类型1:通过结构体变量(对象|实例)访问成员
struct Stu {int id; // 结构体成员char name[20]; } stu; // 结构体变量// 访问成员 stu.name;
-
类型2:通过结构体指针访问成员
-
第1种:指针引用访问成员
struct Stu {int id; // 结构体成员char name[20]; } stu; // 结构体变量 | 对象 | 实例struct Stu *p = &stu; // 指针引用访问成员 p -> name; // 等价于(*p).name
-
第2种:指针解引用间接访问成员
struct Stu {int id; // 结构体成员char name[20]; } stu; // 结构体变量 | 对象 | 实例struct Stu *p = &stu; // 指针解引用访问成员 (*p).name; // 等价于 p -> name
-
-
结构体数组中元素的访问
struct Stu {int id;char name[20];float scores[3]; } stus[3] = {{1,"张三",{67,77,88}},// (stus+1){2,"李四",{90,99,98}},{3,"王五",{88,97,77}} }; // 取数据 -- 下标法 printf("%s,%.2f\n",stus[1].name,stus[1].scores[1]); // 李四 99// 取数据 -- 指针法(->) printf("%s,%.2f\n",stus -> name,stus -> scores[2]); // 张三 88 printf("%s,%.2f\n",(stus+1) -> name,(stus+1) -> scores[2]); // 李四 98 printf("%s,%.2f\n",(*(stus+1)).name,(*(stus+1)).scores[2]); // 李四 98
小贴士:
结构体是自定义数据类型,它是数据类型,用法类似于基本类型的int
结构体数组它是存放结构体对象的数组,类似于int数组存放int数据
基本类型数组怎么用,结构体数组就怎么用--->可以遍历,可以作为形式参数,也可以做指针等
-
-
-
结构体类型的使用案例
结构体可以作为函数的返回类型、形式参数等
举例:
#include <string.h>/*** 定义结构体*/ struct Cat {char *name; // 姓名int age; // 年龄char color[20]; // 颜色 };/*** 结构体类型作为形式参数*/ void test1(struct Cat c) {printf("test1:\n%s,%d,%s\n",c.name, c.age, c.color); }/*** 结构体类型作为形式参数,结构体类型作为返回值类型*/ struct Cat test2(struct Cat c) {return c; }/*** 结构体数组作为形式参数*/ struct Cat test3(struct Cat cats[], int len) {struct Cat *p = cats;for(; p < cats + len; p++){printf("test3:\n%s,%d,%s\n",p -> name, p -> age, p -> color);} }/** * 结构体指针作为形式参数,结构体指针作为返回类型 */ struct Cat *test4(struct Cat *cats, char *name) {struct Cat *p = cats;// 遍历for(; p < cats + 3; p++){if(strcmp(name, p -> name) == 0) return p;}return NULL;// 指针返回空 }struct Cat *test5(struct Cat (*cats)[3], char *name) {//数组指针遍历:用指针偏移for(int i = 0; i < 3; i++){if(strcmp(name, (*cats)[i].name) == 0)return &(*cats)[i]; //*cats是整个数组的指针}return NULL; }int main(int argc,char *argv[]) {// 定义结构体对象struct Cat cat = {"狗狗", 8, "yellow"};// 结构体对象作为实际参数test1(cat);// 结构体作为函数参数和返回值类型struct Cat res_cat = test2(cat);printf("test2:\n%s,%d,%s\n",res_cat.name, res_cat.age, res_cat.color);// 定义结构体数组struct Cat cats[] = {{"汤姆",16,"blue"},{"杰瑞",18,"green"},{"索菲",19,"red"}};// 结构体作为函数的实际参数test3(cats,3);// 结构体指针作为形式参数,结构体指针作为返回类型struct Cat *p = test4(cats,"汤姆");printf("test4:\n%s,%d,%s\n", p -> name, p -> age, p -> color);struct Cat *q = test5(&cats, "汤姆");printf("test5:\n%s,%d,%s\n", q -> name, q -> age, q -> color);return 0; }
结构体类型求大小
字节对齐
-
字节对齐的原因:
-
硬件要求:某些硬件平台(如ARM、x86)要求特定类型的数据必须对齐到特定地址,否则会引发性能下降或硬件异常
-
优化性能:对齐的数据访问速度更快。例如,CPU访问对齐的
int
数据只需一次内存操作,而未对齐的数据可能需要多次操作
-
-
字节对齐规则:
-
默认对齐规则
-
结构体的每个成员按其类型大小和编译器默认对齐数(通常是类型的自然对齐数)对齐
-
结构体的总大小必须是最大对齐数的整数倍
-
-
对齐细节
-
基本类型的对齐数:
char
(1字节)、short
(2字节)、int
(4字节)、double
(8字节) -
结构体成员的对齐:每个成员的起始地址必须是对齐数的整数倍
-
结构体总大小的对齐:结构体的总大小必须是其最大对齐数的整数倍
-
-
#pragma pack(n)
的影响:使用#pragma pack(n)
可以强制指定对齐数为n
(n
为 1、2、4、8、16)。此时:-
每个成员的对齐数取
n
和其类型大小的较小值 -
结构体的总大小必须是
n
和最大对齐数中的较小值的整数倍
-
-
-
对齐示例
-
默认对齐
struct S1 {char c; // 1字节(偏移0)int i; // 4字节(需对齐到4,填充3字节,偏移4-7)double d; // 8字节(需对齐到8,偏移8-15) };
struct S1 { double d; // 8字节(偏移0-7)int i; // 4字节(需对齐到8,偏移8-11)char c; // 1字节(需对齐到12,还需填充3字节) };
struct S1 {char c; // 1字节(偏移0,填充7字节)double d; // 8字节(需对齐到8)int i; // 4字节(需对齐到16,填充4字节) };
总结:结构体中,成员的顺序会影响到结构体最终的大小
-
-
使用
#pragma pack(1)
#pragma pack(1) struct S1 {char c; // 1字节(偏移0)int i; // 4字节(偏移1-4)double d; // 8字节(偏移5-12) }; #pragma pack() // S1 的大小为 13字节
#pragma pack(2) struct S1 {char c; // 1字节(偏移0,填充1字节)int i; // 4字节(偏移2-5)double d; // 8字节(偏移6-13) }; #pragma pack() // S1 的大小为 14字节
#pragma pack(4) struct S1 {char c; // 1字节(偏移0,填充3字节)int i; // 4字节(偏移4-7)double d; // 8字节(偏移8-15) }; #pragma pack() // S1 的大小为 16字节
-
在GNU标准中,可以在定义结构体时,指定对齐规则:
__attribute__((packed)); // 结构体所占内存大小是所有成员所占内存大小之和 ——attribute__((aligned(n))); // 设置结构体占n个字节,如果n比默认值小,n不起作用;n必须是2的次方
案例:
int main(int argc,char *argv[]) {struct Cat{char sex __attribute((aligned(2)));// 1 -- 2int id;// 4char name[20];// 20} __attribute__((packed)); // 结构体所占内存大小是所有成员所占内存大小之和,packed---结构体取消所有填充printf("%ld\n",sizeof(struct Cat));// 默认字节对齐(28)/ 使用packed后(25)return 0; }// 编译结果是26:存在隐藏行为 // 1. aligned(2) 覆盖结构体对齐:GCC 可能将结构体的整体对齐要求设为 max(2, 1) = 2(忽略 id 的 4 字节对齐,因 packed 冲突)。 // 2. 结构体填充规则:总大小需为 2 的倍数 → 25 → 26 字节
柔性数组
定义:柔性数组不占有结构体的大小
语法:
struct St {...char arr[0]; };
案例:
int main(int argc,char *argv[]) {struct Cat{char sex __attribute((aligned(2)));// 1 -- 2int id; // 4char arr[0]; // 0 柔性数组不占用结构体的大小char name[20]; // 20} __attribute__((packed)); // 结构体所占内存大小是所有成员所占内存大小之和printf("%ld\n",sizeof(struct Cat));// 默认字节对齐(28)/ 使用packed后(25)/ 使用aligned之后(26)return 0; }
课堂练习
计算以下结构体的大小
// 定义测试结构体 struct TEST1 {char a;int b; };struct TEST1_1 {char a;int b; }__attribute__((packed));// 取消字节对齐,取消之后,结构体数据类型大小就等于其所有成员的数据类型之和struct TEST1_2 {char a __attribute__((aligned(2)));int b; };struct TEST2 {char a;short c;int b; };struct TEST3 {int num;char name[10];char sex;int age;double score; };struct TEST3_1 {int num;char name[10];char sex;double score;int age; };struct TEST4 {int num;short name[5];char sex;int age;int scores[2]; };int main(int argc,char *argv[]) {// 创建结构体变量struct TEST1 test1;struct TEST2 test2;struct TEST3 test3;struct TEST3_1 test3_1;struct TEST4 test4;struct TEST1_1 test1_1;struct TEST1_2 test1_2;// 计算大小printf("%lu\n",sizeof(test1));// 8printf("%lu\n",sizeof(test2));// 8printf("%lu\n",sizeof(test3));// 32printf("%lu\n",sizeof(test3_1));// 32printf("%lu\n",sizeof(test4));// 28printf("%lu\n",sizeof(test1_1));// 5printf("%lu\n",sizeof(test1_2));// 8return 0; }
共用体/联合体类型
-
定义:使几个不同变量占用同一段内存的结构。共用体按定义中需要存储空间最大的成员来分配存储单元,其他成员也是使用该空间,它们的首地址是相同的
-
定义格式:
union 共用体名称 {数据类型 成员名;数据类型 成员名;... };
-
共用体的定义和结构体类似
-
可以有名字,也可以匿名
-
共用体在定义时也可以定义共用体变量
-
共用体在定义时也可以初始化成员
-
共用体也可以作为形参和返回值类型使用
-
共用体也可以定义共用体变量
-
...
也就是说,结构体的用法,共用体都支持
-
-
注意:
-
共用体弊大于利,尽量少用,一般很少用;
-
共用体变量在某一时刻只能存储一个数据,并且也只能取出一个数
-
共用体所有成员共享同一内存空间,同一时间只能存储一个值,可能导致数据覆盖
-
共用体和结构体都是自定义数据类型,用法类似于基本数据类型
-
共用体可以是共用体的成员,也可以是结构体的成员
-
结构体可以是结构体的成员,也可以是共用体的成员
-
-
-
案例:
// 定义共用体 union S {char a;float b;int c; };// S的大小是4字节// 共用体作为共用体成员 union F {char a;union S s; // 4字节 };// 大小是4字节// 共用体作为结构体的成员 struct G {int a;union S s; };// 大小是8字节// 定义一个结构体 struct H {int a;char b; };// 大小是8字节// 结构体作为结构体成员 struct I {int a;int b;struct H h; };// 大小是16字节// 共用体作为结构体成员 struct J {int a;// 4char b;// 1union S s;// 4 };// 大小是12字节void test1() {// 定义一个共用体union Stu{int num;char sex;double score;};// 定义匿名共用体union{int a;char c;} c;// 匿名共用体,一定要定义出变量名,否则报错printf("%lu,%lu\n",sizeof(union Stu),sizeof(c)); }void test2() {union C{int a;char b;};// 定义变量union C c;// 存储数据c.a = 10;c.b = 'A';printf("%d---%d\n",c.a,c.b); // 65---65c.a += 5; // c.a = 65 + 5printf("%d---%d\n",c.a,c.b); // 70---70union E{char *f;// 8 存储的是 hello world! 的首地址long a;// 8int b;// 4} e = {"hello world!"}; // hello world存储在数据段printf("%s,%ld,%d\n",e.f,e.a,e.b); } int main(int argc,char *argv[]) {test1();test2();return 0; }
相关文章:
C语言基础18
内容提要 构造类型 结构体 共用体/联合体 枚举 typedef 构造类型 数据类型 基本类型/基础类型 整型 短整型:short [int] -- 2字节 基本整型:int -- 4字节 长整型:long [int] -- 32位4字节/64位8字节 长长整型:long long…...
Docker部署Jenkins服务
文章目录 1.下载Jenkins服务2.部署Java21(可选)2.1 安装Java21 3.Maven3.9.9安装4.启动Jenkins5.初始化Jenkins5.1 入门5.2 安装推荐的插件5.3 创建第一个管理员用户5.4 实例配置5.5 Jenkins已就绪5.6 开始使用Jenkins5.7 重启Jenkins 6.配置Jenkins6.1 …...
【题解-Acwing】798. 差分矩阵
题目:798. 差分矩阵 题目描述 输入一个n行m列的整数矩阵,再输入q个操作,每个操作包含五个整数 x1,y1,x2,y2,c,其中 (x1,y1)和 (x2,y2)表示一个子矩阵的左上角坐标和右下角坐标。 每个操作都要将选中的子矩阵中的每个元素的值加…...
linux环境下的硬盘分区格式化工具介绍 fdisk,gdisk,parted,cfdisk,cgdisk,sfdisk,gparted 笔记250407
linux环境下的硬盘分区格式化工具介绍 fdisk,gdisk,parted,cfdisk,cgdisk,sfdisk,gparted 笔记250407 以下是 Linux 系统中常用的 硬盘分区与格式化工具,涵盖命令行和图形界面工具,按功能分类整理: 一、分区管理工具 1. 命令行工具 工具功能…...
Ubuntu 24.04 LTS系统安装RTX 4090显卡驱动和cuda并部署ollama下载DeepSeek模型【自用详细版】
自己捣鼓玩玩哈,正好有机子 1. 安装驱动前的系统配置工作 卸载原有驱动并禁用nouveau sudo apt remove --purge nvidia*sudo cp /etc/modprobe.d/blacklist.conf /etc/modprobe.d/blacklist.conf.backup //备份文件sudo vim /etc/modprobe.d/blacklist.conf //修…...
FogFL: Fog-Assisted Federated Learning for Resource-Constrained IoT Devices
摘要 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 -在本文中,我们提出了一个支持雾的联邦学习框架–FogFL–来促进资源受限的物联网环境中延迟敏感应用的分布式学习。联邦学习(FL)是一种流行的分…...
音视频入门基础:RTCP专题(2)——RTCP协议简介(上)
一、引言 本文对RTCP协议进行简介。在简介之前,请各位先下载RTCP的官方文档《RFC 3550》。《RFC 3550》总共有89页。本文下面所说的“页数”是指在pdf阅读器中显示的页数: 二、RTCP协议简介 本段内容对应《RFC 3550》的第6节。根据《RFC 3550》第17页&…...
oklink js逆向(入口定位)
分析api请求,定位参数 X-Apikey 搜索关键字apikey,发现结果太多 结合搜索结果,搜索关键字 apikey(,只找到5个 断点后定位 可见使用了字符串混淆,所以搜索不到 x-apikey 还可以通过搜索 headers,追踪调用栈的…...
go原子操作和锁的区别是什么?
在Go语言中,原子操作和锁都是用于实现并发编程的同步机制,但它们的工作方式和适用场景有所不同。下面是它们的主要区别: 1. 原子操作(Atomic Operations) 定义:原子操作是一种不可分割的操作,…...
QtConcurrent
以下是 QtConcurrent 的一些常见用法示例: QtConcurrent::run QtConcurrent::run 是最常用的函数,用于在单独的线程中运行一个函数。 运行普通函数 #include <QtConcurrent> #include <QDebug> #include <QThread>void myFunction…...
Git 仓库在内网与 Gitee 间迁移及同步记录
Git 仓库在内网与 Gitee 间迁移及同步记录 在软件开发过程中,常常会遇到需要将代码仓库进行迁移或同步的情况。近期我就碰到了要把 Gitee 代码仓库移植到内网代码仓库,并且后续还得进行同步的需求。这里把整个过程记录下来,方便以后自己参考…...
如何保证mysql和redis的数据一致性
保证 MySQL 和 Redis 的数据一致性是分布式系统中常见的挑战,因为 Redis 作为缓存层,可能存在与底层数据库数据不一致的情况。以下是几种常用的方案及其优缺点对比: 1. 缓存更新策略 (1) Cache-Aside Pattern(旁路缓存模式&#…...
Java学习——day23(反射的对象创建与方法调用)
文章目录 1. 使用反射实例化对象1.1 利用无参构造函数创建对象1.2利用带参构造函数创建对象 2.通过反射调用对象方法2.1 调用公共方法2.2 调用私有方法(需设置访问权限)3. 访问和修改对象的属性3.1 公共属性3.2 私有属性 4. 实践任务4.1工厂类 SimpleFac…...
遇到无法连接香港服务器可能是什么原因导致的呢
遇到无法连接香港服务器的情况时,别急着重启或联系客服,先搞清楚到底是哪里断了链条。问题可能出在服务器本身,也可能是你的本地网络、路由路径、DNS、甚至运营商的“干预”。以下是常见的几个可能原因,建议你可以逐一排查&#x…...
Python----计算机视觉处理(Opencv:道路检测完整版:透视变换,提取车道线,车道线拟合,车道线显示,)
Python----计算机视觉处理(Opencv:道路检测之道路透视变换) Python----计算机视觉处理(Opencv:道路检测之提取车道线) Python----计算机视觉处理(Opencv:道路检测之车道线拟合) Python----计算机视觉处理࿰…...
javaweb自用笔记:Maven分模块设计与开发、Maven继承与聚合、Maven私服
Maven分模块设计与开发 Maven继承与聚合 继承 版本锁定 dependencies引入依赖,dependencyManagement不代表依赖被引入,如果要使用dependencyManagement下的依赖,还需要在dependencies里面定义 聚合 如果没有用聚合,将这个项目打…...
在PyCharm中出现 **全角字符与非英文符号混合输入** 的问题
在PyCharm中出现 全角字符与非英文符号混合输入 的问题(如 124345dfs$¥cvd)࿰…...
数字身份DID协议:如何用Solidity编写去中心化身份合约
本文提出基于以太坊的自主主权身份(SSI)实现方案,通过扩展ERC-734/ERC-735标准构建链上身份核心合约,支持可验证声明、多密钥轮换、属性隐私保护等特性。设计的三层架构体系将身份控制逻辑与数据存储分离,在测试网环境…...
Linux的RPM包管理详解
Linux的RPM包管理详解 引言 RPM(Red Hat Package Manager)是Linux系统中一种重要的软件包管理工具,它以“.rpm”为扩展名,广泛应用于基于Red Hat的Linux发行版,如CentOS、Fedora、openSUSE等。RPM包不仅简化了软件包…...
其它理论原则
ABC理论 假设(Assumption)影响行为(Behavior),行为最终影响结果(Consequence)。 如果产品经理认为同事是一个不讲道理的人,那么产品经理在和他交流时就会产生抵触的行为,…...
C++中的类和对象(上)
1 类的定义 1.1 类定义的格式 1 class为定义类的关键字,Stack为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省 略》。类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数…...
LLaMA-Factory 数据集成从入门到精通
一、框架概述 LLaMA-Factory 框架通过Alpaca/Sharegpt双格式体系实现多任务适配,其中Alpaca专注结构化指令微调(含SFT/DPO/预训练),Sharegpt支持多角色对话及多模态数据集成。核心配置依托 dataset_info.json 实现数据源映射、格…...
高级:JVM面试题深度剖析
一、引言 在Java技术面试中,JVM(Java虚拟机)相关知识是考察重点之一。深入理解JVM的内存模型、垃圾回收机制、类加载机制等,不仅能帮助开发者优化Java应用性能,还能在面试中展现深厚的技术功底。本文将针对这些高频知…...
Spring MVC 中 @ResponseBody 注解深度使用教程
一、注解核心作用 ResponseBody 是 Spring MVC 中处理 响应体内容 的核心注解,主要功能: 跳过视图解析器:直接返回数据而非视图名称自动数据转换:根据返回值类型自动转换响应格式(JSON/XML/纯文本)RESTfu…...
数据结构第一轮复习--第七章查找(包含课程代码)
基于数组实现顺序查找代码 //顺序查找的实现 typedef struct{ //查找表的数据结构(顺序表) ElemType *elem; //指向开辟的动态数组基址 (起始地址) int TableLen; //表的长度 }SSTable; //顺序查找 int Search_Seq(SSTable ST…...
Springboot JPA 集成ShardingSphere
Spring Boot集成JPA与ShardingSphere可通过以下步骤实现分库分表功能,需重点关注依赖配置、分片规则定义及JPA适配问题: 一、依赖配置 1. 引入核心依赖 在pom.xml中添加ShardingSphere和JPA相关依赖: <!-- ShardingSphere JDBC --&…...
详细介绍javaspringboot操控redis的高级特性1. 事务支持2. 发布/订阅3. Pipeline批量操作
Spring Boot 对 Redis 的操作提供了丰富的高级特性,以下是对事务支持、发布 / 订阅、Pipeline 批量操作的详细介绍: 事务支持 原理:Redis 事务是一个单独的隔离操作,它可以包含多个命令,这些命令要么全部执行&#x…...
第一次3D打印,一个简单的小方块(Rhino)
一、建模 打开犀牛,我们选择立方体 我们点击上册的中心点 输入0,然后回车0 而后我们输长度:10,回车确认 同样的,宽度10 高度同样是10 回车确认后,我们得到一个正方形 二、导出模型 我们选择文件—>保存…...
数据分享:汽车测评数据
说明:如需数据可以直接到文章最后关注获取。 1.数据背景 Car Evaluation汽车测评数据集是一个经典的机器学习数据集,最初由 Marko Bohanec 和 Blaz Zupan 创建,并在 1997 年发表于论文 "Classifier learning from examples: Common …...
硬盘分区格式之GPT(GUID Partition Table)笔记250406
硬盘分区格式之GPT(GUID Partition Table)笔记250406 GPT(GUID Partition Table)硬盘分区格式详解 GPT(GUID Partition Table)是替代传统 MBR 的现代分区方案,专为 UEFI(统一可扩展固…...
辉视智慧医院:以科技温度 重塑医疗未来新生态
大家是否想过,医院里的广播对讲系统也能变身‘智慧管家’?今天带您走进辉视智慧医院,看看他们如何用四大黑科技,让医患沟通更暖心、更高效! 一、物联网技术:医疗设备‘开口说话’,广播系统秒变‘…...
Google 发布 Sec-Gemini v1:用 AI 重塑网络安全防御格局?
在网络威胁日益复杂化、自动化程度不断提高的今天,防御方常常感到力不从心。为了扭转这一局面,Google 近日迈出了重要一步,宣布推出专为网络安全领域量身打造的实验性 AI 模型——Sec-Gemini v1。该模型由 Google 内部的 Sec-Gemini 团队成员…...
Android 使用ninja加速编译的方法
ninja的简介 随着Android版本的更迭,makefile体系逐渐增多,导致make单编模块的时间越来越长,每次都需要半个小时甚至更长时间,其原因为每次make都会重新加载所有mk文件,再生成ninja编译,此完整过程十分耗时…...
windterm终端软件使用
windterm终端软件使用 下载安装包:https://github.com/kingToolbox/WindTerm/releases ssh连接: 可以复用vscode连接ssh信息 onekey 相当于服务器主机的用户名和密码 点击配置标签如Linux,输入用户名如root, identity file指定本地公钥&a…...
《操作系统真象还原》第六章——完善内核
文章目录 [toc]前言调用约定和混合编程调用约定混合编程 实现打印函数print.S显卡的端口控制实现单个字符打印put_char定义数据类型put_char编码修改内核main.c验证put_char 实现字符串打印put_str 结语 前言 学完上一章后,我们已经完成了一个操作系统最基本的三个…...
上海餐饮市场数据分析与可视化
上海作为中国的经济中心和国际化大都市,其餐饮市场具有高度的多样性和竞争性。随着消费者需求的不断变化,餐饮行业的从业者和投资者需要深入了解市场现状和趋势,以便制定更有效的商业策略。本文将通过数据分析和可视化技术,深入探讨上海餐饮市场的现状和趋势,为餐饮从业者…...
不花钱也能玩GPT-4o,国内可用
家人们!最近GPT-4o生图功能真的离谱到不真实,各种吉卜力、宫崎骏、3D风格等刷爆小红书。 由于只有GPT官网,只有Plus用户才能用,很多小伙伴们都没有机会体验过GPT,本期就分享一个国内也能直接玩的方法。 第一步&#x…...
ResNet改进(22):提升特征选择能力的卷积神经网络SKNet
在计算机视觉领域,残差网络(ResNet)一直是图像分类任务中的经典架构。本文将介绍一种改进版的ResNet18,它融合了选择性核(SK)机制,能够自适应地调整不同感受野的特征权重,从而提升模型性能。下面我们将详细解析这个实现代码。 一、代码概述 这个Python脚本实现了一个带有S…...
实战代码:esp32-cam按钮控制手机拍照V1.0
#include <WiFi.h> #include <HTTPClient.h> // WiFi设置 const char* ssid “MIFI-020806-2.4G”; const char* password “12345678”; // 静态IP配置 IPAddress staticIP(192, 168, 1, 32); // 设置为固定IP IPAddress gateway(192, 168, 1, 1); // 网关地址…...
Base64是密码吗?编码与加密的本质区别
(本文完全由deepseek生成,特此声明!) 引言:一个让开发者“翻车”的经典误区 我们常看到类似这样的提问: “我用Base64加密了用户的密码,为什么还是被黑客破解了?” “Base64解…...
原理图输出网表及调入
一、输出网表操作步骤 (1)选中.dsn文件,选者N或进入tools下拉列表选择Creat Netlists (2)导出网表后的文件 二、网表的导入 (1)执行菜单命令“File-Import-Logic/netlist”,将原理…...
C++ 模板的应用——智能指针、STL库
#include "head.h" #include <stdio.h> using namespace std;void registerUser(vector<string>& number,vector<string>& passwd){string username;string Passwd;cout << "请输入账号:" << endl;cin >> use…...
基于层次建模与交叉注意力融合的医学视觉问答系统(HiCA-VQA)详解
论文地址:https://arxiv.org/pdf/2504.03135 一、论文结构概述 这篇论文提出了一种针对医学视觉问答(Medical Visual Question Answering, Med-VQA)的层次化建模框架 HiCA-VQA,旨在解决现有方法在层次化语义建模和跨模态融合上的不足。以下是论文的核心结构: 引言 介…...
比较与分析敏捷开发方法:XP、Scrum、FDD等的特点与适用场景
目录 前言1. 极限编程 (XP)1.1 极限编程的核心特点1.2 极限编程的适用场景 2. Scrum2.1 Scrum的核心特点2.2 Scrum的适用场景 3. 水晶方法 (Crystal)3.1 水晶方法的核心特点3.2 水晶方法的适用场景 4. 特征驱动开发 (FDD)4.1 特征驱动开发的核心特点4.2 特征驱动开发的适用场景…...
ICMP 协议深度解析
ICMP 协议深度解析 一、协议定位与核心作用 ICMP(互联网控制报文协议)是IP协议体系的"哨兵系统",专用于网络状态监控与异常反馈。其核心价值体现在: 轻量级控制:仅传递关键状态信息,不承载业务…...
C语言基础20
内容提要 预处理 库文件 预处理 C语言编译步骤 预处理 编译 汇编 链接 什么是预处理 预处理就是在源文件(.c文件)编译之前,所进行的一部分预备操作,这部分操作是由预处理程序自动完成。当源文件在编译时,编译…...
conda常用命令
要查看使用conda创建的虚拟环境,可以按照以下步骤操作: 打开终端或命令行工具:确保你已经打开了终端或命令行界面,以便输入conda命令。 输入命令查看环境列表: 使用以下任一命令查看conda创建的虚拟环境:…...
Ubunut18.04 离线安装MySQL 5.7.35
一、环境准备 1.1 官方下载MySQL5.7.35 完整包 1.2 上传包 & 解压 上传包名称是:mysql-server_5.7.35-1ubuntu18.04_amd64.deb-bundle.tar # 切换到上传目录 cd /home/MySQL # 解压: tar -xvf mysql-server_5.7.35-1ubuntu18.04_amd64.deb-bundle…...
地图与图层操作
地图文档本质上就是存储在磁盘上的地图,包括地理数据、图名、图例等一系列要素,当完成地图制作、图层要素标注及符号显示设置后,可以将其作为图层文件保存到磁盘中,在一个图层文件中,包括了定义如何在地图上描述地理数…...
红宝书第三十一讲:通俗易懂的包管理器指南:npm 与 Yarn
红宝书第三十一讲:通俗易懂的包管理器指南:npm 与 Yarn 资料取自《JavaScript高级程序设计(第5版)》。 查看总目录:红宝书学习大纲 一、基础概念 包管理器:帮你自动下载和管理第三方代码库(如…...