day18 结构体

news2025/1/12 4:04:51

有参宏和函数的区别

1.展开时机:有参宏而言,在预处理阶段展开,而函数在调用时才展开

2.内存使用:有参宏而言,占用的是所在函数的空间,而函数在调用时会单独开辟空间

3.效率上:有参宏的效率比函数有的效率高

4.有参宏是宏定义,只替换不计算不做正确性检查,而函数调用要符合函数的调用标准,形参会进行计算

结构体

概念:结构体是由相同数据类型或不同数据类型构成的连续存储的变量的集合,结构体属于构造数据类型

定义格式

struct  结构体名

{

成员类型1 成员变量1;

成员类型2 成员变量2;

......

}

注意事项:

1.struct是结构体的关键字,在C语言中定义结构体时不能省略

2.struct后面跟的是结构体类型名,类似于int  float  double

3.所有的结构体成员属性使用一对花括号包裹,每个成员之间使用分号隔开

4.成员变量的类型,可以是任意类型(可以是基本数据类型,也可以是构造数据类型、指针类型、空类型)

5.花括号后的分号绝对不能省略

struct  Student     //若没有student(结构体名)后续便不能继续定义结构体变量
{
    int num;        //学号
    char name[20];       //姓名
    double score;       //成绩
    char sex;           //性别
    char TEL[11];        //手机号
}s1,s2;
//定义结构体类型时顺便定义了两个结构体变量

/*struct student s1,s2;*/

结构体可以定义在程序的任何地方,可以定义在函数体内也可以定义在函数体外,但是必须要定义在使用之前    一般定义在函数体外,分文件编译时,通常定义在头文件内

结构体变量的初始化,也有三种方式,初始化时所有成员是花括号包裹,每个成员之间使用逗号隔开

//定义一个结构体类型
struct  Student
{
    int num;        //学号
    char name[20];       //姓名
    double score;       //成绩
    char sex;           //性别
    char TEL[11];        //手机号
};

//在程序中
struct  Student  s1 = {1001, "张三", 99.5, 'M', "13888888888"};    //定义了一个结构体变量并初始化
//定义一个结构体类型
struct  Student
{
    int num;        //学号
    char name[20];       //姓名
    double score;       //成绩
    char sex;           //性别
    char TEL[11];        //手机号
}s1 = {1002, "李四", 99.8, 'W',13888888888};

定义结构体变量并给部分成员初始化

struct  Student
{
    int num;        //学号
    char name[20];       //姓名
    double score;       //成绩
    char sex;           //性别
    char TEL[11];        //手机号
};

//在程序中
struct  Student  s1 = {.num="张三", .score=99.5};    //定义了一个结构体变量并初始化

2.4结构体类型访问成员

1.结构体变量访问成员,使用成员.运算符来完成

        使用方法:变量名.成员名;

2.结构体指针访问成员,使用成员运算符->来完成

        使用方法:指针变量->成员名;

3.虽然这两个运算符是双目运算符但是拥有较高的优先级。比单目运算符优先级高

4.上面两个运算执行后结果是 成员类型,跟结构体变量和结构体指针就没有关系了

5.不要试图通过结构体变量名,操作所有成员,只能通过成员运算符一个一个操作

6.结构体变量支持两种运算:取地址运算、赋值运算

7.结构体类型中,也可以有另一个结构体变量,访问最里层的成员时需要成员运算符一级一级找到最低一级 

#include<myhead.h>

struct Student;      //结构体类型的声明

//定义一个生日类型
struct Birthday
{
    int year;     //年份
    int month;      //月份
    int day;       //日
};


//定义结构体类型
struct Student
{
    int num;    //学号
    char name[20];      //姓名
    double score;      //成绩

    struct Birthday bir;      //生日

} s1 = {1002, "张三", 99.5};        //分号不能省略

int main(int argc, const char *argv[])
{
    //使用结构体类型定义变量并初始化
    struct Student s2 = {1001, "zhangpp", 99, {2000,2,20}};

    struct Student s3 = {.num=1003, .score=100};   //对部分成员初始化

    s1.num = 9527;       //使用成员运算符对成员进行操作
    printf("s1.num = %d, s1.name=%s, s1.score=%.2lf\n", \
            s1.num, s1.name, s1.score);
    //printf("%s\n", s1);        //不可以通过结构体变量名输出所有成员
    printf("&s1 = %p\n", &s1);    //输出的是s1的地址

    struct Student *ptr = &s1;    //结构体指针变量
    ptr->num = 9999;
    printf("ptr->num = %d, ptr->name=%s, ptr->score=%.2lf\n", \
            ptr->num, ptr->name, ptr->score);

    //结构体变量支持赋值运算
    s1 = s2;
    printf("ptr->num = %d, ptr->name=%s, ptr->score=%.2lf\n", \
            ptr->num, ptr->name, ptr->score);

    //访问结构体成员中的结构体变量
    s1.bir.year = 2024;     //需要使用成员运算符一级一级找到最低一级
    ptr->bir.month = 3;    
    printf("生日:%d-%d-%d\n", ptr->bir.year, ptr->bir.month, ptr->bir.day);
    
    return 0;
}

结构体数组

1.本质是一个数值,每个元素都是结构体变量

2.结构体数组的定义和使用跟普通数组一致,但是,访问到数组元素时,每个元素需要继续是成员运算符找到其结构体成员进行操作

#include<myhead.h>

//定义一个英雄类型
struct Hero
{
    char name[20];       //英雄名称
    int kill;           //击杀人头数
    int die;            //死亡此处
    int assist;         //辅助次数
};

//定义函数,录入英雄本局比赛的信息
void input_hero_msg(struct Hero *ptr, int n)
{
    //录入信息
    for(int i=0; i<n; i++)
    {
        printf("请输入第%d个英雄的名称:", i+1);
        scanf("%s", ptr[i].name);     //(ptr+i)->name
        printf("请输入第%d个英雄的人头数:", i+1);
        scanf("%d", &ptr[i].kill);
        printf("请输入第%d个英雄的死亡数:", i+1);
        scanf("%d", &ptr[i].die);
        printf("请输入第%d个英雄的辅助数:", i+1);
        scanf("%d", &ptr[i].assist);

        printf("\n");
    }

    printf("录入成功\n");
}

//定义输出函数
void output_hero_msg(struct Hero *ptr, int n)
{
    printf("本局比赛结算如下:\n");
    printf("英雄\tkill\tdie\tassist\n");
    for(int i=0; i<n; i++)
    {
        printf("%s\t%d\t%d\t%d\n", ptr[i].name,ptr[i].kill, ptr[i].die, ptr[i].assist);
    }
}

//定义求mvp函数
struct Hero mvp_hero(struct Hero *ptr, int n)
{
    struct Hero mvp = ptr[0];   //将第一个英雄当做mvp
    for(int i=0; i<n; i++)
    {
        //拿着当前mvp的数据跟任意一个进行比较
        if( mvp.kill*0.9+mvp.assist*0.5-mvp.die*0.4  < \
            ptr[i].kill*0.9+ptr[i].assist*0.5-ptr[i].die*0.4 )
        {
            //更新mvp
            mvp = ptr[i];
        }
    }

    //将mvp返回
    return mvp;

}



int main(int argc, const char *argv[])
{
    //定义数组存储五个英雄
    struct Hero hero[5];    //hero[0]---hero[4]

    //录入英雄的信息
    input_hero_msg(hero, 5);

    //输出英雄信息
    output_hero_msg(hero, 5);

    //求 mvp 
    struct Hero res = mvp_hero(hero, 5);
    printf("本局比赛的mvp为:%s,%d,%d,%d\n", \
            res.name,res.kill,res.die,res.assist);


    
    return 0;
}

结构体大小

1.定义结构体类型时,系统不分配内存空间,只有使用结构体类型定义变量时才分配内存空间

2.系统为结构体变量分配的空间是连续的,系统会将结构体每个成员看成一个整体进行操作

3.结构体大小:是每个成员变量所占内存大小之和-->字节对齐原则

        结构体变量实际大小>=各个成员变量所占内存之和

4.C语言中,一个空的结构体所占内存为0字节

#include<myhead.h>

struct AA            //空结构体所占内存为0字节
{
};

struct BB            //只有一个字符成员
{
    char value;      // 1 
};

struct CC               //有两个成员
{
    short key;          // 1120
    char value;
};

struct DD           //有三个成员
{
    short key;
    char value;
    int temp;           //11203333
};

struct EE          //两个成员
{
    char value;
    int temp;      //10002222
};

struct FF            //有四个成员
{
    int num;
    char value;
    char *ptr;
    short key;   // 111120003333333344000000
};


struct GG            //有四个成员
{
    char *ptr;
    int num;
    char value;
    short key;   // 1111111122223044
};


struct HH                  //一个普通变量和一个结构体变量
{
    short num;
    struct EE value;    //110010002222
};

struct II           //一个普通变量和一个结构体变量
{
    char temp;
    struct GG g;     // 100000001111111122223044

};


int main(int argc, const char *argv[])
{
    printf("sizeof(struct AA) = %zd\n", sizeof(struct AA));    //0
    printf("sizeof(struct BB) = %zd\n", sizeof(struct BB));    //1
    printf("sizeof(struct CC) = %zd\n", sizeof(struct CC));    //4
    struct CC c;
    printf("&c=%p, &c.value=%p, &c.key = %p\n", \
            &c, &c.value, &c.key);

    printf("sizeof(struct DD) = %zd\n", sizeof(struct DD));    //8
    printf("sizeof(struct EE) = %zd\n", sizeof(struct EE));    //8
    printf("sizeof(struct FF) = %zd\n", sizeof(struct FF));    //24
    printf("sizeof(struct GG) = %zd\n", sizeof(struct GG));    //16
    printf("sizeof(struct HH) = %zd\n", sizeof(struct HH));    //12
    struct HH h;
    printf("&h=%p, &h.num=%p, &h.value = %p, &h.value.value=%p, &h.value.temp=%p\n", \
            &h, &h.num, &h.value, &h.value.value, &h.value.temp);
    printf("sizeof(struct II) = %zd\n", sizeof(struct II));    //24
    
    return 0;
}

特殊关键字的使用

const

1.在定义变量后,变量有两个属性,读属性(获取值)写属性(修改值)

2.const:保护数据的作用,给变量以常属性

3.const的用法

        const可以修饰普通变量:修饰普通变量时表示给该变量以常属性(不能通过该变量进行写操作)

        const修饰的局部变量,必须进行初始化,如果不初始化,则为随机值,并且后期不能更改,可以使用指针指向该变量,使用指针更改其值是没有问题的

#include<myhead.h>

int main(int argc, const char *argv[])
{
    //1、const修饰普通变量
    const int num = 520;

    printf("num = %d\n", num);   //具有读属性

    //num = 1314;       //不能通过变量名进行更改
    
    int *ptr = &num;    //定义指针指向num

    *ptr = 1314;       //使用指针更改num的值
    printf("num = %d\n", num);   //具有读属性

    
    return 0;
}

const修饰指针变量

const int*ptr:保护的是指针指向内存空间的值,指针的指向可以改变,但是不能通过改变指针改变其指向内存空间的值

int const *ptr:保护的是指针指向内存空间的值,指针的指向可以改变,但是不能通过改变指针改变其指向内存空间的值

int *const ptr:保护的是指针的值(指针指向)。指针指向不可以改变,但是可以通过指针改变其指向的内存空间中的值

const int *const ptr:全部进行保护,既不能改变指针的指向,也不能通过指针改变其指向内存空间中的值

#include<myhead.h>

int main(int argc, const char *argv[])
{
    int num = 520;      //普通变量
    int key = 1314;

    //定义指针变量
    const int *ptr1 = &num;   //保护指针指向的内存空间中的值
    //*ptr1 = 666;          //执行不成功 不能进行写操作
    printf("*ptr1 = %d\n", *ptr1);
    ptr1 = &key;             //可以改变指针的指向

    //定义指针变量
    int const *ptr2 = &num;   //保护指针指向的内存空间中的值
    //*ptr2 = 666;          //执行不成功 不能进行写操作
    printf("*ptr2 = %d\n", *ptr2);
    ptr2 = &key;             //可以改变指针的指向

    //定义指针变量
    int * const ptr3 = &num;  //保护的是指针的指向(指针的值)
    *ptr3 = 666;          //可以通过指针改变指向的内存空间中的值
    printf("*ptr3 = %d\n", *ptr3);   //读取数据
    //ptr3 = &key;               //不可以改变指针的值(指向)
    

    //定义指针变量
    const int *const ptr4 = &num;
    //*ptr4 = 999;          //不可以通过指针改变指向的内存空间中的值
    //ptr4 = &key;          //不可以改变指针的指向


    return 0;
}

const修饰函数的形式参数,表示保护形参数据不被修改

#include<myhead.h>

//保护形参的指向不被修改
void fun(int * const ptr)
{
    //如果没有保护指针的指向,那么下面会出现段错误
    if(ptr=NULL)
    {

    }


    *ptr = 1314;
}

//保护传入的指针指向的内存空间中的值不会在函数体内被更改
void hun(const char *ptr)
{
    //如果没有保护指针指向的空间的值,则下面程序会出现段错误
    ptr[0] = 'A';
}


int main(int argc, const char *argv[])
{
    int num = 520;

    fun(&num);        //调用函数传递地址


    printf("num = %d\n", num);


    hun("hello a");   //调用函数传递一个字符串
    
    return 0;
}

const修饰函数的返回值,表示保护函数的返回结果不被修改,常用于指针函数

*fun() = 520
ubuntu@ubuntu:day17$ cat 08const.c 
#include<myhead.h>

//const修饰的函数,称为常函数,表示保护返回结果不能被修改
const int *fun()
{
    static int num = 520;

    return &num;         //指针函数返回静态局部变量的地址
}




int main(int argc, const char *argv[])
{
    //*fun() = 1314;       //不能被修改,因为函数由const修饰了

    printf("*fun() = %d\n", *fun());     //?
    
    return 0;
}

static

1> static修饰局部变量,表示相当于在函数体内定义一个全局变量,该变量的生命周期不会随着所在函数的开始而开始结束而结束,并且static修饰的变量的空间不依附所在函数。其生命周期从程序运行时就开始了。

2> static修饰全局变量,表示该变量只能在所在文件中使用,不能被其他文件所引入

3> static修饰函数时,表示该函数也只能在该文件中被使用,其他文件不能使用

extern

1.可以在某个文件中使用extern来引入其他文件中的全局变量

2.在局部变量和全局变量同名时,函数体内优先使用局部变量,如果非要使用全局变量,可以使用extern引入后使用

#include<myhead.h>

int num = 520;      //全局变量


int main(int argc, const char *argv[])
{
    int num = 1314;           //局部变量

    if(1)
    {
        extern int num;     //引入外部变量

        printf("num = %d\n", num);         //?
    }

    return 0;
}

作业

1> 使用结构体数组完成班级学生管理系统,学生类型中包含 (学号、姓名、成绩、性别、TEL)

2> 完成菜单选项

3> 功能1:信息录入,提示并输入班级人数,完成每个学生信息的录入

4> 功能2:信息展示

5> 功能3:添加一个学生操作

6> 功能4:提示并输入一个学号,并将该学号对应的学生信息删除

7> 功能5:提示并输入一个学生姓名,更改其联系方式

8> 功能6:提示并输入一个学生姓名,展示该学生的所有信息

9> 功能7:将学生按成绩进行降序排序

10> 功能0:退出系统

#include<luochen.h>
#include "homework.h"

int menu()
{
	int menu;
	printf("请输入你想要实现的功能:\n");
	printf("1.信息录入\n");
	printf("2.信息展示\n");
	printf("3.添加成绩\n");
	printf("4.删除成绩\n");
	printf("5.更改成绩\n");
	printf("6.查找学生\n");
	printf("7.降序排列\n");
	printf("0.退出系统\n");
	scanf ("%d",&menu);
	return menu;
}
void gn1(struct student *body,int *n)
{

	printf("请输入需要录入的人数:");
	scanf("%d",n);
	for (int i=0;i<*n;i++)
	{
		printf("请输入第%d同学的学号:",i+1);
		scanf("%d",&body[i].num);
		printf("请输入第%d同学的姓名:",i+1);
		scanf("%s",body[i].name);
		printf("请输入第%d同学的成绩:",i+1);
		scanf("%d",&body[i].score);
		printf("请输入第%d的性别(m/w):",i+1);
		getchar();
		scanf("%c",&body[i].sex);
		printf("请输入第%d同学的电话:",i+1);
		scanf("%s",body[i].tel);
		printf("\n");

	}  printf("录入成功\n");
       printf("\n");
}
 void gn2(struct student *body,int *n)
{
		//信息展示

	for(int i=0;i<*n;i++)
	{
		printf("%d/t%s/t%d/t%c/t%s\n",body[i].num,body[i].name,body[i].score,body[i].sex,body[i].tel);

	}
}

 void gn3(struct student *body,int *n)
{
	printf("请输入学生学号:");
	scanf("%d",&body[*n].num);
	printf("请输入学生姓名:");
	scanf("%s",body[*n].name);
	printf("请输入学生成绩:");
	scanf("%d",&body[*n].score);
	printf("请输入的性别(m/w):");
	getchar();
	scanf("%c",&body[*n].sex);
	printf("请输入学生电话:");
	scanf("%s",body[*n].tel);
	*n+=1;
	printf("添加成功\n");
}

 void gn4(struct student *body,int *n)
{
	int a;
	int b=0;
	//判断是否删除成功
	printf("请输入学生学号");
	scanf("%d",&a);
	for (int i=0;i<*n;i++)
	{
	if(a==body[i].num)
	{
		for (int j=i;j<*n-1;j++)
		{
		body[j]=body[j+1];
		}(*n)--;
		b=1;
	}
	}
	if(b)
	{
	printf("删除成功\n");
	}else{
	printf("为查询到该同学\n");
	}

}
 void gn5(struct student *body,int *n)
{
	int a=0;
	//判断是否更改成功
	char name[20]="";
	printf("请输入更改电话的学生姓名:");
	scanf("%s",name);
	for (int i=0;i<*n;i++)
	{
	if(strcmp(name,body[i].name)==0)
	{
	printf("请输入更改后的电话:");
	scanf("%s",body[i].tel);
    a=1;
	}
	}if(a)
	{
	printf("更改成功\n");
	}else{
	printf("未查询到该学生\n");

	}

}

void gn6(struct student *body,int *n)
{
	//查找学生信息
	char name[20]="";
	int a=0;
	printf("请输入你要查找的学生姓名:");
	scanf("%s",name);
	for (int i=0;i<*n;i++)
	{
		if(strcmp(name,body[i].name)==0)
		{
		printf("%d\t%s\t%d\t%c\t%s\n",body[i].num,body[i].name,body[i].score,body[i].sex,body[i].tel);
		a=1;
		}
	}if(!a)
	{
	printf("查询失败\n");
	}
}
void gn7(struct student *body,int *n)
	//降序排列
{
	for (int i=1;i<*n;i++)
	{
	for (int j=0;j<*n-i;i++)
	{
		if(body[j].score<body[j+1].score)
		{
		struct student temp=body[j];
		body[j]=body[j+1];
		body[j+1]=temp;
		}
	}
	}printf("排序成功\n");

}
#include <luochen.h>
#include "homework.h"
int main(int argc, const char *argv[])
{
	struct student body[MAX];
	int num = 0;
	//定义学生人数
	while (1)
    {
		switch(menu())
		{
			case 1:{
				   gn1(body,&num);
				   }break;
			case 2:{
				   gn2(body,&num);
				   }break;
			case 3:{
				   gn3(body,&num);
				   }break;
			case 4:{
				   gn4(body,&num);
				   }break;
	    	case 5:{
				   gn5(body,&num);
				   }break;
			case 6:{
				   gn6(body,&num);
				   }break;
			case 7:{
				   gn7(body,&num);
				   }
			case 0:exit(0);
				    break;
			default:
				   printf("输入有误,请重新输入\n");
		}

	}
	
	return 0;
}
#ifndef HOMEWORK_H
#define HOMEWORK_H
#define MAX 100
struct student
{
	int num;//记录学号
	char name[20];//记录名字
	int score;//记录成绩
	char sex;//记录性别
	char tel[11];//记录电话号码
};

void gn1(struct student *body,int *n);
int menu();
void gn2(struct student *body,int *n);
void gn3(struct student *body,int *n);
void gn4(struct student *body,int *n);
void gn5(struct student *body,int *n);
void gn6(struct student *body,int *n);
void gn7(struct student *body,int *n);

#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2248218.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C嘎嘎探索篇:栈与队列的交响:C++中的结构艺术

C嘎嘎探索篇&#xff1a;栈与队列的交响&#xff1a;C中的结构艺术 前言&#xff1a; 小编在之前刚完成了C中栈和队列&#xff08;stack和queue&#xff09;的讲解&#xff0c;忘记的小伙伴可以去我上一篇文章看一眼的&#xff0c;今天小编将会带领大家吹奏栈和队列的交响&am…

Postman设置接口关联,实现参数化

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 postman设置接口关联 在实际的接口测试中&#xff0c;后一个接口经常需要用到前一个接口返回的结果&#xff0c; 从而让后一个接口能正常执行&#xff0c;这…

大模型的RAG微调与Agent:提升智能代理的效率与效果

目录 ​编辑 引言 RAG模型概述 检索阶段 生成阶段 RAG模型的微调 数据集选择 损失函数设计 微调策略 超参数调整 RAG模型在智能代理中的应用 客户服务 信息检索 内容创作 决策支持&#xff1a; 结论 引言 在人工智能的快速发展中&#xff0c;大型预训练模型&a…

前端---CSS(部分用法)

HTML画页面--》这个页面就是页面上需要的元素罗列起来&#xff0c;但是页面效果很差&#xff0c;不好看&#xff0c;为了让页面好看&#xff0c;为了修饰页面---》CSS CSS的作用&#xff1a;修饰HTML页面 用了CSS之后&#xff0c;样式和元素本身做到了分离的效果。---》降低了代…

【R语言管理】Pycharm配置R语言及使用Anaconda管理R语言虚拟环境

目录 使用Anaconda创建R语言虚拟环境1. 安装Anaconda2. 创建R语言虚拟环境 Pycharm配置R语言1. 安装Pycharm2. R Language for IntelliJ插件 参考 使用Anaconda创建R语言虚拟环境 1. 安装Anaconda Anaconda的安装可参见另一博客-【Python环境管理工具】Anaconda安装及使用教程…

互联网视频推拉流EasyDSS视频直播点播平台视频转码有哪些技术特点和应用?

视频转码本质上是一个先解码再编码的过程。在转码过程中&#xff0c;原始视频码流首先被解码成原始图像数据&#xff0c;然后再根据目标编码标准、分辨率、帧率、码率等参数重新进行编码。这样&#xff0c;转换前后的码流可能遵循相同的视频编码标准&#xff0c;也可能不遵循。…

Linux Shell 脚本题目集

1、执行 ping 命令对指定主机进行测试&#xff0c;以确定该主机是否处于存活状态并输出相应结果。 #!/bin/bashread -p "请输入主机号&#xff1a;" pc # 读取用户输入的主机号if [ -z "$pc" ];then # 检查用户输入是否为空echo "主…

使用ENSP实现默认路由

一、项目拓扑 二、项目实现 1.路由器AR1配置 进入系统试图 sys将路由器命名为R1 sysname R1关闭信息中心 undo info-center enable 进入g0/0/0接口 int g0/0/0将g0/0/0接口IP地址配置为2.2.2.1/24 ip address 2.2.2.1 24进入g0/0/1接口 int g0/0/1将g0/0/1接口IP地址配置为1.…

【vue3实现微信小程序】每日专题与分页跳转的初步实现

快速跳转&#xff1a; 我的个人博客主页&#x1f449;&#xff1a;Reuuse博客 新开专栏&#x1f449;&#xff1a;Vue3专栏 参考文献&#x1f449;&#xff1a;uniapp官网 免费图标&#x1f449;&#xff1a;阿里巴巴矢量图标库 ❀ 感谢支持&#xff01;☀ 前情提要 &#x…

小程序-基于java+SpringBoot+Vue的网上花店微信小程序设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

Opencv+ROS实现颜色识别应用

目录 一、工具 二、原理 概念 本质 三、实践 添加发布话题 主要代码 四、成果 五、总结 一、工具 opencvros ubuntu18.04 摄像头 二、原理 概念 彩色图像&#xff1a;RGB&#xff08;红&#xff0c;绿&#xff0c;蓝&#xff09; HSV图像&#xff1a;H&#xff0…

解决 java -jar 报错:xxx.jar 中没有主清单属性

问题复现 在使用 java -jar xxx.jar 命令运行 Java 应用程序时&#xff0c;遇到了以下错误&#xff1a; xxx.jar 中没有主清单属性这个错误表示 JAR 文件缺少必要的启动信息&#xff0c;Java 虚拟机无法找到应用程序的入口点。本文将介绍该错误的原因以及如何通过修改 pom.xm…

JavaWeb——SpringBoot原理

10.1. 配置优先级 10.1.1. 配置文件 properties > yml(推荐) > yaml 10.1.2. Java系统属性、命令行参数 命令行参数 > Java系统属性 > 配置文件 10.2. Bean管理 10.2.1. 手动获取bean ApplicationContext&#xff0c;IOC容器对象 10.2.2. bean作用域 10.2.3.…

【AI绘画】Midjourney进阶:色调详解(上)

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;Midjourney中的色彩控制为什么要控制色彩&#xff1f;为什么要在Midjourney中控制色彩&#xff1f; &#x1f4af;色调白色调淡色调明色调 &#x1f4af…

STM32F103外部中断配置

一、外部中断 在上一节我们介绍了STM32f103的嵌套向量中断控制器&#xff0c;其中包括中断的使能、失能、中断优先级分组以及中断优先级配置等内容。 1.1 外部中断/事件控制器 在STM32f103支持的60个可屏蔽中断中&#xff0c;有一些比较特殊的中断&#xff1a; 中断编号13 EXTI…

【Vue3+Pinia】Vue新一代状态管理器Pinia

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【消息序列】详解(7):剖析回环模式--设备测试的核心利器

目录 一、概述 1.1. 本地回环模式 1.2. 远程环回模式 二、本地回环模式&#xff08;Local Loopback mode&#xff09; 2.1. 步骤 1&#xff1a;主机进入本地环回模式 2.2. 本地回环测试 2.2.1. 步骤 2a&#xff1a;主机发送HCI数据包并接收环回数据 2.2.2. 步骤 2b&…

大厂也在用的分布式链路追踪:TraceIdFilter + MDC + Skywalking

痛点 查线上日志时&#xff0c;同一个 Pod 内多线程日志交错&#xff0c;很难追踪每个请求对应的日志信息。 日志收集工具将多个 Pod 的日志收集到同一个数据库中后&#xff0c;情况就更加混乱不堪了。 解决 TraceId MDC 前端每次请求时&#xff0c;添加 X-App-Trace-Id 请…

leetcode - 2116. Check if a Parentheses String Can Be Valid

Description A parentheses string is a non-empty string consisting only of ‘(’ and ‘)’. It is valid if any of the following conditions is true: It is ().It can be written as AB (A concatenated with B), where A and B are valid parentheses strings.It ca…

如何启动 Docker 服务:全面指南

如何启动 Docker 服务:全面指南 一、Linux 系统(以 Ubuntu 为例)二、Windows 系统(以 Docker Desktop 为例)三、macOS 系统(以 Docker Desktop for Mac 为例)四、故障排查五、总结Docker,作为一种轻量级的虚拟化技术,已经成为开发者和运维人员不可或缺的工具。它允许用…