当前位置: 首页 > news >正文

C语言基础18

内容提要

  • 构造类型

    • 结构体

    • 共用体/联合体

    • 枚举

    • typedef

构造类型

数据类型

  1. 基本类型/基础类型

    • 整型

      • 短整型: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字节

  2. 指针类型

    • 数据类型*:int* char* float*等 -- 8字节

    • void*:通用类型指针(万能指针) -- 8字节

  3. 空值类型

    • void:无返回值,无形参(不能定义变量)

  4. 构造类型(自定义类型)

    • 结构体类型: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;
    }
结构体类型求大小
字节对齐
  • 字节对齐的原因:

    1. 硬件要求:某些硬件平台(如ARM、x86)要求特定类型的数据必须对齐到特定地址,否则会引发性能下降或硬件异常

    2. 优化性能:对齐的数据访问速度更快。例如,CPU访问对齐的int数据只需一次内存操作,而未对齐的数据可能需要多次操作

  • 字节对齐规则:

    1. 默认对齐规则

      • 结构体的每个成员按其类型大小和编译器默认对齐数(通常是类型的自然对齐数)对齐

      • 结构体的总大小必须是最大对齐数的整数倍

    2. 对齐细节

      • 基本类型的对齐数char(1字节)、short(2字节)、int(4字节)、double(8字节)

      • 结构体成员的对齐:每个成员的起始地址必须是对齐数的整数倍

      • 结构体总大小的对齐:结构体的总大小必须是其最大对齐数的整数倍

    3. #pragma pack(n)的影响:使用#pragma pack(n)可以强制指定对齐数为nn为 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 构造类型 数据类型 基本类型/基础类型 整型 短整型&#xff1a;short [int] -- 2字节 基本整型&#xff1a;int -- 4字节 长整型&#xff1a;long [int] -- 32位4字节/64位8字节 长长整型&#xff1a;long long…...

Docker部署Jenkins服务

文章目录 1.下载Jenkins服务2.部署Java21&#xff08;可选&#xff09;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. 差分矩阵

题目&#xff1a;798. 差分矩阵 题目描述 输入一个n行m列的整数矩阵&#xff0c;再输入q个操作&#xff0c;每个操作包含五个整数 x1,y1,x2,y2,c&#xff0c;其中 (x1,y1)和 (x2,y2)表示一个子矩阵的左上角坐标和右下角坐标。 每个操作都要将选中的子矩阵中的每个元素的值加…...

linux环境下的硬盘分区格式化工具介绍 fdisk,gdisk,parted,cfdisk,cgdisk,sfdisk,gparted 笔记250407

linux环境下的硬盘分区格式化工具介绍 fdisk,gdisk,parted,cfdisk,cgdisk,sfdisk,gparted 笔记250407 以下是 Linux 系统中常用的 硬盘分区与格式化工具&#xff0c;涵盖命令行和图形界面工具&#xff0c;按功能分类整理&#xff1a; 一、分区管理工具 1. 命令行工具 工具功能…...

Ubuntu 24.04 LTS系统安装RTX 4090显卡驱动和cuda并部署ollama下载DeepSeek模型【自用详细版】

自己捣鼓玩玩哈&#xff0c;正好有机子 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

摘要 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 -在本文中&#xff0c;我们提出了一个支持雾的联邦学习框架–FogFL–来促进资源受限的物联网环境中延迟敏感应用的分布式学习。联邦学习&#xff08;FL&#xff09;是一种流行的分…...

音视频入门基础:RTCP专题(2)——RTCP协议简介(上)

一、引言 本文对RTCP协议进行简介。在简介之前&#xff0c;请各位先下载RTCP的官方文档《RFC 3550》。《RFC 3550》总共有89页。本文下面所说的“页数”是指在pdf阅读器中显示的页数&#xff1a; 二、RTCP协议简介 本段内容对应《RFC 3550》的第6节。根据《RFC 3550》第17页&…...

oklink js逆向(入口定位)

分析api请求&#xff0c;定位参数 X-Apikey 搜索关键字apikey&#xff0c;发现结果太多 结合搜索结果&#xff0c;搜索关键字 apikey(&#xff0c;只找到5个 断点后定位 可见使用了字符串混淆&#xff0c;所以搜索不到 x-apikey 还可以通过搜索 headers&#xff0c;追踪调用栈的…...

go原子操作和锁的区别是什么?

在Go语言中&#xff0c;原子操作和锁都是用于实现并发编程的同步机制&#xff0c;但它们的工作方式和适用场景有所不同。下面是它们的主要区别&#xff1a; 1. 原子操作&#xff08;Atomic Operations&#xff09; 定义&#xff1a;原子操作是一种不可分割的操作&#xff0c;…...

QtConcurrent

以下是 QtConcurrent 的一些常见用法示例&#xff1a; QtConcurrent::run QtConcurrent::run 是最常用的函数&#xff0c;用于在单独的线程中运行一个函数。 运行普通函数 #include <QtConcurrent> #include <QDebug> #include <QThread>void myFunction…...

Git 仓库在内网与 Gitee 间迁移及同步记录

Git 仓库在内网与 Gitee 间迁移及同步记录 在软件开发过程中&#xff0c;常常会遇到需要将代码仓库进行迁移或同步的情况。近期我就碰到了要把 Gitee 代码仓库移植到内网代码仓库&#xff0c;并且后续还得进行同步的需求。这里把整个过程记录下来&#xff0c;方便以后自己参考…...

如何保证mysql和redis的数据一致性

保证 MySQL 和 Redis 的数据一致性是分布式系统中常见的挑战&#xff0c;因为 Redis 作为缓存层&#xff0c;可能存在与底层数据库数据不一致的情况。以下是几种常用的方案及其优缺点对比&#xff1a; 1. 缓存更新策略 (1) Cache-Aside Pattern&#xff08;旁路缓存模式&#…...

Java学习——day23(反射的对象创建与方法调用)

文章目录 1. 使用反射实例化对象1.1 利用无参构造函数创建对象1.2利用带参构造函数创建对象 2.通过反射调用对象方法2.1 调用公共方法2.2 调用私有方法&#xff08;需设置访问权限&#xff09;3. 访问和修改对象的属性3.1 公共属性3.2 私有属性 4. 实践任务4.1工厂类 SimpleFac…...

遇到无法连接香港服务器可能是什么原因导致的呢

遇到无法连接香港服务器的情况时&#xff0c;别急着重启或联系客服&#xff0c;先搞清楚到底是哪里断了链条。问题可能出在服务器本身&#xff0c;也可能是你的本地网络、路由路径、DNS、甚至运营商的“干预”。以下是常见的几个可能原因&#xff0c;建议你可以逐一排查&#x…...

Python----计算机视觉处理(Opencv:道路检测完整版:透视变换,提取车道线,车道线拟合,车道线显示,)

Python----计算机视觉处理&#xff08;Opencv:道路检测之道路透视变换) Python----计算机视觉处理&#xff08;Opencv:道路检测之提取车道线&#xff09; Python----计算机视觉处理&#xff08;Opencv:道路检测之车道线拟合&#xff09; Python----计算机视觉处理&#xff0…...

javaweb自用笔记:Maven分模块设计与开发、Maven继承与聚合、Maven私服

Maven分模块设计与开发 Maven继承与聚合 继承 版本锁定 dependencies引入依赖&#xff0c;dependencyManagement不代表依赖被引入&#xff0c;如果要使用dependencyManagement下的依赖&#xff0c;还需要在dependencies里面定义 聚合 如果没有用聚合&#xff0c;将这个项目打…...

在PyCharm中出现 **全角字符与非英文符号混合输入** 的问题

在PyCharm中出现 全角字符与非英文符号混合输入 的问题&#xff08;如 &#xff11;&#xff12;&#xff14;&#xff13;&#xff14;&#xff15;&#xff44;&#xff46;&#xff53;&#xff04;&#xffe5;&#xff43;&#xff56;&#xff44;&#xff09;&#xff0…...

数字身份DID协议:如何用Solidity编写去中心化身份合约

本文提出基于以太坊的自主主权身份&#xff08;SSI&#xff09;实现方案&#xff0c;通过扩展ERC-734/ERC-735标准构建链上身份核心合约&#xff0c;支持可验证声明、多密钥轮换、属性隐私保护等特性。设计的三层架构体系将身份控制逻辑与数据存储分离&#xff0c;在测试网环境…...

Linux的RPM包管理详解

Linux的RPM包管理详解 引言 RPM&#xff08;Red Hat Package Manager&#xff09;是Linux系统中一种重要的软件包管理工具&#xff0c;它以“.rpm”为扩展名&#xff0c;广泛应用于基于Red Hat的Linux发行版&#xff0c;如CentOS、Fedora、openSUSE等。RPM包不仅简化了软件包…...

其它理论原则

ABC理论 假设&#xff08;Assumption&#xff09;影响行为&#xff08;Behavior&#xff09;&#xff0c;行为最终影响结果&#xff08;Consequence&#xff09;。 如果产品经理认为同事是一个不讲道理的人&#xff0c;那么产品经理在和他交流时就会产生抵触的行为&#xff0c…...

C++中的类和对象(上)

1 类的定义 1.1 类定义的格式 1 class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后面分号不能省 略》。类体中内容称为类的成员&#xff1a;类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数…...

LLaMA-Factory 数据集成从入门到精通

一、框架概述 LLaMA-Factory 框架通过Alpaca/Sharegpt双格式体系实现多任务适配&#xff0c;其中Alpaca专注结构化指令微调&#xff08;含SFT/DPO/预训练&#xff09;&#xff0c;Sharegpt支持多角色对话及多模态数据集成。核心配置依托 dataset_info.json 实现数据源映射、格…...

高级:JVM面试题深度剖析

一、引言 在Java技术面试中&#xff0c;JVM&#xff08;Java虚拟机&#xff09;相关知识是考察重点之一。深入理解JVM的内存模型、垃圾回收机制、类加载机制等&#xff0c;不仅能帮助开发者优化Java应用性能&#xff0c;还能在面试中展现深厚的技术功底。本文将针对这些高频知…...

Spring MVC 中 @ResponseBody 注解深度使用教程

一、注解核心作用 ResponseBody 是 Spring MVC 中处理 响应体内容 的核心注解&#xff0c;主要功能&#xff1a; 跳过视图解析器&#xff1a;直接返回数据而非视图名称自动数据转换&#xff1a;根据返回值类型自动转换响应格式&#xff08;JSON/XML/纯文本&#xff09;RESTfu…...

数据结构第一轮复习--第七章查找(包含课程代码)

基于数组实现顺序查找代码 //顺序查找的实现 typedef struct{ //查找表的数据结构&#xff08;顺序表&#xff09; ElemType *elem; //指向开辟的动态数组基址 &#xff08;起始地址&#xff09; int TableLen; //表的长度 }SSTable; //顺序查找 int Search_Seq(SSTable ST…...

Springboot JPA 集成ShardingSphere

Spring Boot集成JPA与ShardingSphere可通过以下步骤实现分库分表功能&#xff0c;需重点关注依赖配置、分片规则定义及JPA适配问题&#xff1a; 一、依赖配置 1‌. 引入核心依赖‌ 在pom.xml中添加ShardingSphere和JPA相关依赖&#xff1a; <!-- ShardingSphere JDBC --&…...

详细介绍javaspringboot操控redis的高级特性1. 事务支持2. 发布/订阅3. Pipeline批量操作

Spring Boot 对 Redis 的操作提供了丰富的高级特性&#xff0c;以下是对事务支持、发布 / 订阅、Pipeline 批量操作的详细介绍&#xff1a; 事务支持 原理&#xff1a;Redis 事务是一个单独的隔离操作&#xff0c;它可以包含多个命令&#xff0c;这些命令要么全部执行&#x…...

第一次3D打印,一个简单的小方块(Rhino)

一、建模 打开犀牛&#xff0c;我们选择立方体 我们点击上册的中心点 输入0&#xff0c;然后回车0 而后我们输长度&#xff1a;10&#xff0c;回车确认 同样的&#xff0c;宽度10 高度同样是10 回车确认后&#xff0c;我们得到一个正方形 二、导出模型 我们选择文件—>保存…...

数据分享:汽车测评数据

说明&#xff1a;如需数据可以直接到文章最后关注获取。 1.数据背景 Car Evaluation汽车测评数据集是一个经典的机器学习数据集&#xff0c;最初由 Marko Bohanec 和 Blaz Zupan 创建&#xff0c;并在 1997 年发表于论文 "Classifier learning from examples: Common …...

硬盘分区格式之GPT(GUID Partition Table)笔记250406

硬盘分区格式之GPT&#xff08;GUID Partition Table&#xff09;笔记250406 GPT&#xff08;GUID Partition Table&#xff09;硬盘分区格式详解 GPT&#xff08;GUID Partition Table&#xff09;是替代传统 MBR 的现代分区方案&#xff0c;专为 UEFI&#xff08;统一可扩展固…...

辉视智慧医院:以科技温度 重塑医疗未来新生态

大家是否想过&#xff0c;医院里的广播对讲系统也能变身‘智慧管家’&#xff1f;今天带您走进辉视智慧医院&#xff0c;看看他们如何用四大黑科技&#xff0c;让医患沟通更暖心、更高效&#xff01; 一、物联网技术&#xff1a;医疗设备‘开口说话’&#xff0c;广播系统秒变‘…...

Google 发布 Sec-Gemini v1:用 AI 重塑网络安全防御格局?

在网络威胁日益复杂化、自动化程度不断提高的今天&#xff0c;防御方常常感到力不从心。为了扭转这一局面&#xff0c;Google 近日迈出了重要一步&#xff0c;宣布推出专为网络安全领域量身打造的实验性 AI 模型——Sec-Gemini v1。该模型由 Google 内部的 Sec-Gemini 团队成员…...

Android 使用ninja加速编译的方法

ninja的简介 随着Android版本的更迭&#xff0c;makefile体系逐渐增多&#xff0c;导致make单编模块的时间越来越长&#xff0c;每次都需要半个小时甚至更长时间&#xff0c;其原因为每次make都会重新加载所有mk文件&#xff0c;再生成ninja编译&#xff0c;此完整过程十分耗时…...

windterm终端软件使用

windterm终端软件使用 下载安装包&#xff1a;https://github.com/kingToolbox/WindTerm/releases ssh连接&#xff1a; 可以复用vscode连接ssh信息 onekey 相当于服务器主机的用户名和密码 点击配置标签如Linux&#xff0c;输入用户名如root, identity file指定本地公钥&a…...

《操作系统真象还原》第六章——完善内核

文章目录 [toc]前言调用约定和混合编程调用约定混合编程 实现打印函数print.S显卡的端口控制实现单个字符打印put_char定义数据类型put_char编码修改内核main.c验证put_char 实现字符串打印put_str 结语 前言 学完上一章后&#xff0c;我们已经完成了一个操作系统最基本的三个…...

上海餐饮市场数据分析与可视化

上海作为中国的经济中心和国际化大都市,其餐饮市场具有高度的多样性和竞争性。随着消费者需求的不断变化,餐饮行业的从业者和投资者需要深入了解市场现状和趋势,以便制定更有效的商业策略。本文将通过数据分析和可视化技术,深入探讨上海餐饮市场的现状和趋势,为餐饮从业者…...

不花钱也能玩GPT-4o,国内可用

家人们&#xff01;最近GPT-4o生图功能真的离谱到不真实&#xff0c;各种吉卜力、宫崎骏、3D风格等刷爆小红书。 由于只有GPT官网&#xff0c;只有Plus用户才能用&#xff0c;很多小伙伴们都没有机会体验过GPT&#xff0c;本期就分享一个国内也能直接玩的方法。 第一步&#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是密码吗?编码与加密的本质区别

&#xff08;本文完全由deepseek生成&#xff0c;特此声明&#xff01;&#xff09;‌ 引言&#xff1a;一个让开发者“翻车”的经典误区‌ 我们常看到类似这样的提问&#xff1a; “我用Base64加密了用户的密码&#xff0c;为什么还是被黑客破解了&#xff1f;” “Base64解…...

原理图输出网表及调入

一、输出网表操作步骤 &#xff08;1&#xff09;选中.dsn文件&#xff0c;选者N或进入tools下拉列表选择Creat Netlists &#xff08;2&#xff09;导出网表后的文件 二、网表的导入 &#xff08;1&#xff09;执行菜单命令“File-Import-Logic/netlist”&#xff0c;将原理…...

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&#xff08;互联网控制报文协议&#xff09;是IP协议体系的"哨兵系统"&#xff0c;专用于网络状态监控与异常反馈。其核心价值体现在&#xff1a; 轻量级控制&#xff1a;仅传递关键状态信息&#xff0c;不承载业务…...

C语言基础20

内容提要 预处理 库文件 预处理 C语言编译步骤 预处理 编译 汇编 链接 什么是预处理 预处理就是在源文件&#xff08;.c文件&#xff09;编译之前&#xff0c;所进行的一部分预备操作&#xff0c;这部分操作是由预处理程序自动完成。当源文件在编译时&#xff0c;编译…...

conda常用命令

要查看使用conda创建的虚拟环境&#xff0c;可以按照以下步骤操作&#xff1a; 打开终端或命令行工具&#xff1a;确保你已经打开了终端或命令行界面&#xff0c;以便输入conda命令。 输入命令查看环境列表&#xff1a; 使用以下任一命令查看conda创建的虚拟环境&#xff1a…...

Ubunut18.04 离线安装MySQL 5.7.35

一、环境准备 1.1 官方下载MySQL5.7.35 完整包 1.2 上传包 & 解压 上传包名称是&#xff1a;mysql-server_5.7.35-1ubuntu18.04_amd64.deb-bundle.tar # 切换到上传目录 cd /home/MySQL # 解压&#xff1a; tar -xvf mysql-server_5.7.35-1ubuntu18.04_amd64.deb-bundle…...

地图与图层操作

地图文档本质上就是存储在磁盘上的地图&#xff0c;包括地理数据、图名、图例等一系列要素&#xff0c;当完成地图制作、图层要素标注及符号显示设置后&#xff0c;可以将其作为图层文件保存到磁盘中&#xff0c;在一个图层文件中&#xff0c;包括了定义如何在地图上描述地理数…...

红宝书第三十一讲:通俗易懂的包管理器指南:npm 与 Yarn

红宝书第三十一讲&#xff1a;通俗易懂的包管理器指南&#xff1a;npm 与 Yarn 资料取自《JavaScript高级程序设计&#xff08;第5版&#xff09;》。 查看总目录&#xff1a;红宝书学习大纲 一、基础概念 包管理器&#xff1a;帮你自动下载和管理第三方代码库&#xff08;如…...