C++基础知识(三)之结构体、共同体、枚举、引用、函数重载

news2025/2/19 17:11:06

九、结构体、共同体和枚举

1、结构体的基本概念

结构体是用户自定义的类型,可以将多种数据的表示合并到一起,描述一个完整的对象。

使用结构体有两个步骤:1)定义结构体描述(类型);2)创建结构体变量。

1)定义结构体描述

定义结构体描述的语法:

struct 结构体名

{

成员一的数据类型  成员名一;

成员二的数据类型  成员名二;

成员三的数据类型  成员名三;

......

成员n的数据类型  成员名n;

};

注意:

  • 结构体名是标识符。

  • 结构体的成员可以是任意数据类型。

  • 定义结构体描述的代码可以放在程序的任何地方,一般放在main函数的上面或头文件中。

  • 结构体成员可以用C++的类(如string),但是不提倡。

  • 在C++中,结构体中可以有函数,但是不提倡。

  • 在C++11中,定义结构体的时候可以指定缺省值。

2)创建结构体变量

创建结构体变量的语法:

struct 结构体名 结构体变量名;

也可以为结构体成员赋初始值。

struct 结构体名 结构体变量名={成员一的值, 成员二的值,......, 成员n的值};

C++11可以不写等于号。

如果大括号内未包含任何东西或只写一个0,全部的成员都将被设置为0。

struct 结构体名 结构体变量名={0};

注意:

在C++中,struct关键字可以不写。

可以在定义结构体的时候创建结构体变量。

3)使用结构体

在C++程序中,用成员运算符(.)来访问结构体的每个成员。结构体中的每个成员具备普通变量的全部特征。

语法:结构体变量名.结构体成员名;

4)占用内存的大小

用sizeof运算符可以得到整个结构体占用内存的大小。

注意:整个结构体占用内存的大小不一定等于全部成员占用内存之和。

内存对齐:#pragma pack(字节数)

合理使用内存对齐规则,某些节省内存的做法可能毫无意义。

5)清空结构体

创建的结构体变量如果没有初始化,成员中有垃圾值。

用memset()函数可以把结构体中全部的成员清零。(只适用于C++基本数据类型)

bzero()函数也可以。

6)复制结构体

用memcpy()函数把结构体中全部的元素复制到另一个相同类型的结构体(只适用于C++基本数据类型)。

也可以直接用等于号(只适用于C++基本数据类型)。

示例:

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。
#pragma pack(8)

// 超女基本信息结构体st_girl,存放了超女全部的数据项。
struct st_girl
{
    char name[21];        // 姓名。
    int age;                     // 年龄。
    double weight;        // 体重(kg)。
    char sex;                   // 性别:X-女;Y-男。
    bool yz;                    // 颜值:true-漂亮;false-不漂亮。
};

int main()
{
    st_girl stgirl{"西施",26,33.8,'X',true};        // 创建结构体变量。
    
    cout << "sizeof(st_girl)=" << sizeof(st_girl) << endl;   

    memset(&stgirl, 0, sizeof(stgirl));

    cout << "姓名:" << stgirl.name << ",年龄:" << stgirl.age << ",体重:" << stgirl.weight
        << ",性别:" << stgirl.sex << ",颜值:" << stgirl.yz << endl;
}

2、结构体指针

结构体是一种自定义的数据类型,用结构体可以创建结构体变量。

1)基本语法

在C++中,用不同类型的指针存放不同类型变量的地址,这一规则也适用于结构体。如下:

struct st_girl girl;     // 声明结构体变量girl。

struct st_girl *pst=&girl;  // 声明结构体指针,指向结构体变量girls。

通过结构体指针访问结构体成员,有两种方法:

(*指针名).成员变量名   // (*pst).name和(*pst).age 

或者:

指针名->成员变量名   // pst->name和*pst->age 

在第一种方法中,圆点.的优先级高于,(指针名)两边的括号不能少。如果去掉括号写成(指针名).成员变量名,那么相当于(指针名.成员变量名),意义就完全不一样了。

在第二种方法中,->是一个新的运算符。

上面的两种方法是等效的,程序员通常采用第二种方法,更直观。

注意:与数组不一样,结构体变量名没有被解释为地址。

2)用于函数的参数

如果要把结构体传递给函数,实参取结构体变量的地址,函数的形参用结构体指针。

如果不希望在函数中修改结构体变量的值,可以对形参加const约束。

3)用于动态分配内存

用结构体指针指向动态分配的内存的地址。

#define _CRT_SECURE_NO_WARNINGS  // 如果要使用C标准库的字符串函数,需要加上这一行代码
#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

struct st_girl
{
    char name[21];        // 姓名。
    int age;                     // 年龄。
    double weight;        // 体重(kg)。
    char sex;                   // 性别:X-女;Y-男。
    bool yz;                    // 颜值:true-漂亮;false-不漂亮。
};

void func(const st_girl* pst)
{
    cout << "姓名:" << pst->name << ",年龄:" << pst->age << ",体重:" << pst->weight
        << ",性别:" << pst->sex << ",颜值:" << pst->yz << endl;
}

int main()
{
    // st_girl stgirl={"西施",26,33.8,'X',true};        // 创建结构体变量。
    st_girl* stgirl = new st_girl({ "西施",26,33.8,'X',true });
    // memset(stgirl, 0, sizeof(st_girl));

    cout << "姓名:" << stgirl->name << ",年龄:" << stgirl->age << ",体重:" << stgirl->weight
             << ",性别:" << stgirl->sex << ",颜值:" << stgirl->yz << endl;

    func(stgirl);

    cout << "姓名:" << stgirl->name << ",年龄:" << stgirl->age << ",体重:" << stgirl->weight
        << ",性别:" << stgirl->sex << ",颜值:" << stgirl->yz << endl;

    delete stgirl;
}

3、结构体数组

结构体可以被定义成数组变量,本质上与其它类型的数组变量没有区别。

声明结构体数组的语法:struct 结构体类型 数组名[数组长度];

初始化结构体数组,要结合使用初始化数组的规则和初始化结构体的规则。

struct st_girl girls[2]={{"西施",26,43.8,'X',true},{"西瓜",25,52.8,'X',false}};

使用结构体数组可以用数组表示法,也可以用指针表示法。

4、结构体中的指针

如果结构体中的指针指向的是动态分配的内存地址:

  • 对结构体用sizeof运算可能没有意义。

  • 对结构体用memset()函数可能会造成内存泄露。

  • C++的字符串string中有一个指针,指向了动态分配内存的地址。

struct string

{

​	char *ptr;  // 指向动态分配内存的地址。

​	......

}

5、共同体

共同体(共用体、联合体)是一种数据格式,它能存储不同的数据类型,但是,在同一时间只能存储其中的一种类型。

声明共同体的语法:

union 共同体名

{

成员一的数据类型  成员名一;

成员二的数据类型  成员名二;

成员三的数据类型  成员名三;

......

成员n的数据类型  成员名n;

};

注意:

  • 共同体占用内存的大小是它最大的成员占用内存的大小(内存对齐)。

  • 全部的成员使用同一块内存。

  • 共同体中的值为最后被赋值的那个成员的值。

  • 匿名共同体没有名字,可以在定义的时候创建匿名共同体变量(VS和Linux有差别),也可以嵌入结构体中。

应用场景:

  • 当数据项使用两种或更多种格式(但不会同时使用)时,可节省空间(嵌入式系统)。

  • 用于回调函数的参数(相当于支持多种数据类型)。

示例一:

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

union udata         // 声明共同体udata。
{
	int        a;
	double b;
	char     c[25];
} ;

int main()
{
	udata data;     // 定义共同体变量。

	cout << "sizeof(data)=" << sizeof(data) << endl;  //输出32,存在内存对齐,为8的整数倍

	cout << "data.a的地址是:" << (void*)&data.a << endl;
	cout << "data.b的地址是:" << (void*)&data.b << endl;
	cout << "data.c的地址是:" << (void*)&data.c << endl;
	
	data.a = 3;
	data.b = 8.8;
	strcpy(data.c, "我是一只傻傻鸟。");
	cout << "data.a=" << data.a << endl;
	cout << "data.b=" << data.b << endl;
	cout << "data.c=" << data.c << endl;
}

sizeof(data)=32
data.a的地址是:00000054A0F8F7E8
data.b的地址是:00000054A0F8F7E8
data.c的地址是:00000054A0F8F7E8
data.a=-943009074
data.b=-1.92562e-20
data.c=我是一只傻傻鸟。

6、枚举

枚举是一种创建符号常量的方法。

枚举的语法:

enum 枚举名 { 枚举量1 , 枚举量2 , 枚举量3, ......, 枚举量n };

例如:

enum colors { red , yellow , blue };

这条语句完成了两项工作:

  • 让colors成了一种新的枚举类型的名称,可以用它创建枚举变量。

  • 将red、yellow、blue作为符号常量,默认值是整数的0、1、2。

注意:

用枚举创建的变量取值只能在枚举量范围之内。

枚举的作用域与变量的作用域相同。

可以显式的设置枚举量的值(必须是整数)。

enum colors {red=1,yellow=2,blue=3};

可以只显式的指定某些枚举量的值(枚举量的值可以重复)。

enum colors {red=10,yellow,blue};   //10,11,12

可以将整数强制转换成枚举量,语法:枚举类型(整数)

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

int main()
{
	enum colors { red=0, yellow=1, blue=2, other=3 };    // 创建枚举类型colors。

	colors cc = yellow;           // 创建枚举变量,并赋初始值。
	//colors cc = colors(1);           // 创建枚举变量,并赋初始值。
	
	cout << "red=" << red << ",yellow=" << yellow << ",blue=" << blue << ",other=" << other << endl;

	switch (cc)
	{
		case red:			cout << "红色。\n"; break;
		case yellow:	cout << "黄色。\n"; break;
		case blue:		cout << "蓝色。\n"; break;
		default:			cout << "未知。\n"; 
	}
}

十、引用

1、引用的基本概念

引用变量是C++新增的复合类型。

引用是已定义的变量的别名。

引用的主要用途是用作函数的形参和返回值。

声明/创建引用的语法:数据类型 &引用名=原变量名;

注意:

  • 引用的数据类型要与原变量名的数据类型相同。

  • 引用名和原变量名可以互换,它们值和内存单元是相同的。

  • 必须在声明引用的时候初始化,初始化后不可改变。

  • C和C++用&符号来指示/取变量的地址,C++给&符号赋予了另一种含义。

示例:

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

int main()
{
	// 声明 / 创建引用的语法:数据类型 & 引用名 = 原变量名;
	int a = 3;          // 声明普通的整型变量。
	int& ra = a;      // 创建引用ra,ra是a的别名。
	
	cout << " a的地址是:" << &a  << ", a的值是:" <<  a  << endl;
	cout << "ra的地址是:" << &ra << ",ra的值是:" << ra << endl;
	
	ra = 5;    

	cout << " a的地址是:" << &a << ", a的值是:" << a << endl;
	cout << "ra的地址是:" << &ra << ",ra的值是:" << ra << endl;
}

a的地址是:000000A3C975F794, a的值是:3
ra的地址是:000000A3C975F794,ra的值是:3
a的地址是:000000A3C975F794, a的值是:5
ra的地址是:000000A3C975F794,ra的值是:5

2、引用的本质

引用是指针常量的伪装。

引用是编译器提供的一个有用且安全的工具,去除了指针的一些缺点,禁止了部分不安全的操作。

变量是什么?变量就是一个在程序执行过程中可以改变的量。

换一个角度,变量是一块内存区域的名字,它代表了这块内存区域,当我们对变量进行修改的时候,会引起内存区域中内容的改变。

在计算机看来,内存区域根本就不存在什么名字,它仅有的标志就是它的地址,因此我们若想修改一块内存区域的内容,只有知道他的地址才能实现。

所谓的变量只不过是编译器给我们进行的一种抽象,让我们不必去了解更多的细节,降低我们的思维跨度而已。

程序员拥有引用,但编译器仅拥有指针(地址)。

引用的底层机制实际上是和指针一样的。不要相信有别名,不要认为引用可以节省一个指针的空间,因为这一切不会发生,编译器还是会把引用解释为指针。

引用和指针本质上没有区别。

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

int main()
{
	// 声明 / 创建引用的语法:数据类型 & 引用名 = 原变量名;
	// 语法:数据类型 * const 变量名;
	int a = 3;                         // 声明普通的整型变量。
	int& ra = a;                    // 创建引用ra,ra是a的别名。               把int&替换成int* const   把a替换成&a
	int* const rb = &a;        // 声明指针常量rb,让它指向变量a。
	
	cout << " a的地址是:" << &a  << ",  a的值是:" <<  a  << endl;
	cout << "ra的地址是:" << &ra << ", ra的值是:" << ra << endl;     // 把&ra替换成ra,把ra替换成*ra
	cout << "rb的值是  :" << rb << ",*rb的值是:" << *rb << endl;
	
	ra = 5;    

	cout << " a的地址是:" << &a << ",  a的值是:" << a << endl;
	cout << "ra的地址是:" << &ra << ", ra的值是:" << ra << endl;
	cout << "rb的值是  :" << rb << ",*rb的值是:" << *rb << endl;
}

a的地址是:000000E3807AFB84,  a的值是:3
ra的地址是:000000E3807AFB84, ra的值是:3
rb的值是  :000000E3807AFB84,*rb的值是:3
a的地址是:000000E3807AFB84,  a的值是:5
ra的地址是:000000E3807AFB84, ra的值是:5
rb的值是  :000000E3807AFB84,*rb的值是:5

3、引用用于函数的参数

把函数的形参声明为引用,调用函数的时候,形参将成为实参的别名。

这种方法也叫按引用传递或传引用。(传值、传地址、传引用只是说法不同,其实都是传值。)

引用的本质是指针,传递的是变量的地址,在函数中,修改形参会影响实参。

1)传引用的代码更简洁。

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

void func1(int no, string str)    // 传值。
{
	no = 8; 
	str = "我有一只小小鸟。";
	cout << "亲爱的" << no << "号:" << str << endl;
}

void func2(int* no, string* str)    // 传地址。
{
	*no = 8;
	*str = "我有一只小小鸟。";
	cout << "亲爱的" << *no << "号:" << *str << endl;
}

void func3(int &no, string &str)    // 传引用。
{
	no = 8;
	str = "我有一只小小鸟。";
	cout << "亲爱的" << no << "号:" << str << endl;
}

int main()
{
	int bh = 3;      // 超女的编号。
	string message = "我是一只傻傻鸟。";          // 向超女表白的内容。

	//func1(bh, message);                  // 传值。
	//func2(&bh, &message);            // 传地址。
	func3(bh, message);                  // 传引用。
	
	cout << "亲爱的" << bh << "号:" << message << endl;
}

2)传引用不必使用二级指针。

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

void func1(int** p)      // 传地址,实参是指针的地址,形参是二级指针。
{
	*p = new int(3);       // p是二级指针,存放指针的地址。
	cout << "func1内存的地址是:" << *p << ",内存中的值是:" << **p << endl;
}

void func2(int*& p)     // 传引用,实参是指针,形参是指针的别名。
{
	p = new int(3);         // p是指针的别名。
	cout << "func2内存的地址是:" << p << ",内存中的值是:" << *p << endl;
}

int main()
{
	int* p = nullptr;    // 存放在子函数中动态分配内存的地址。

	func1(&p);      // 传地址,实参填指针p的地址。
	//func2(p);      // 传引用,实参填指针p。

	cout << "main 内存的地址是:" << p << ",内存中的值是:" << *p << endl;

	delete p;
}

3)引用的属性和特别之处。

4、引用的形参和const

如果引用的数据对象类型不匹配,当引用为const时,C++将创建临时变量,让引用指向临时变量。

什么时候将创建临时变量呢?

  • 引用是const。

  • 数据对象的类型是正确的,但不是左值。

  • 数据对象的类型不正确,但可以转换为正确的类型。

结论:如果函数的实参不是左值或与const引用形参的类型不匹配,那么C++将创建正确类型的匿名变量,将实参的值传递给匿名变量,并让形参来引用该变量。

将引用形参声明为const的理由有三个:

  • 使用const可以避免无意中修改数据的编程错误。

  • 使用const使函数能够处理const和非const实参,否则将只能接受非const实参。

  • 使用const,函数能正确生成并使用临时变量。

左值是可以被引用的数据对象,可以通过地址访问它们,例如:变量、数组元素、结构体成员、引用和解引用的指针。

非左值包括字面常量(用双引号包含的字符串除外)和包含多项的表达式。

5、引用用于函数的返回值

传统的函数返回机制与值传递类似。

函数的返回值被拷贝到一个临时位置(寄存器或栈),然后调用者程序再使用这个值。

double m=sqrt(36);    // sqrt()是求平方根函数。

sqrt(36)的返回值6被拷贝到临时的位置,然后赋值给m。

cout << sqrt(25);

sqrt(25)的返回值5被拷贝到临时的位置,然后传递给cout。

如果返回的是一个结构体,将把整个结构体拷贝到临时的位置。

如果返回引用不会拷贝内存。

语法:

返回值的数据类型& 函数名(形参列表);

注意:

  • 如果返回局部变量的引用,其本质是野指针,后果不可预知。

  • 可以返回函数的引用形参、类的成员、全局变量、静态变量。

  • 返回引用的函数是被引用的变量的别名,将const用于引用的返回类型。

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

const int &func2(int &ra)    // 返回的是引用。
{
	ra++;
	cout << "ra的地址是:" << &ra << ",ra=" << ra << endl;
	return ra;
}

int main()
{
	int a = 3;
	const int& b = func2(a);      // 返回的是引用。

	cout << " a的地址是:" << &a << ", a=" << a << endl;
	cout << " b的地址是:" << &b << ", b=" << b << endl;

	// func2(a) = 10;             // 返回引有的函数是被引用的变量的别名。

	// cout << " a的地址是:" << &a << ", a=" << a << endl;
	// cout << " b的地址是:" << &b << ", b=" << b << endl;
}

6、各种形参的使用场景

传值、传地址和传引用的指导原则《C++ Primer Plus》

1)如果不需要在函数中修改实参

  • 如果实参很小,如C++内置的数据类型或小型结构体,则按值传递。

  • 如果实参是数组,则使用const指针,因为这是唯一的选择(没有为数组建立引用的说法)。

  • 如果实参是较大的结构,则使用const指针或const引用。

  • 如果实参是类,则使用const引用,传递类的标准方式是按引用传递(类设计的语义经常要求使用引用)。

2)如果需要在函数中修改实参

  • 如果实参是内置数据类型,则使用指针。只要看到func(&x)的调用,表示函数将修改x。

  • 如果实参是数组,则只能使用指针。

  • 如果实参是结构体,则使用指针或引用。

  • 如果实参是类,则使用引用。

当然,这只是一些指导原则,很可能有充分的理由做出其他的选择。

例如:对于基本类型,cin使用引用,因此可以使用cin>>a,而不是cin>>&a。

十一、函数重载

1、函数的默认参数

默认参数是指调用函数的时候,如果不书写实参,那么将使用的一个缺省值。

语法:返回值 函数名(数据类型 参数=值, 数据类型 参数=值,……);

注意:

  • 如果函数的声明和定义是分开书写的,在函数声明中书写默认参数,函数的定义中不能书写默认参数。

  • 函数必须从右到左设置默认参数。也就是说,如果要为某个参数设置默认值,则必须为它后面所有的参数设置默认值。

  • 调用函数的时候,如果指定了某个参数的值,那么该参数前面所有的参数都必须指定。

示例:

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

void func(int bh,const string &name="西施", const string& message="我喜欢你。")    // 向超女表白的函数。
{
	cout << "亲爱的"<<name<<"("<<bh<<"):" << message << endl;
}

int main()
{
	func(3,"冰冰","我是一只傻傻鸟。"); 
	func(5);
}

2、函数重载

函数重载(函数多态)是指设计一系列同名函数,让它们完成相同(似)的工作。

C++允许定义名称相同的函数,条件是它们的特征(形参的个数、数据类型和排列顺序)不同。

#1    int func(short a  ,string b);

#2    int func(int a   ,string b);

#3    int func(double a,string b);

#4    int func(int a   ,string b, int len);

#5    int func(string b , int a);

调用重载函数的时候,在代码中我们用相同的函数名,但是,后面的实参不一样,编译器根据实参与重载函数的形参进行匹配,然后决定调用具体的函数,如果匹配失败,编译器将视为错误。

在实际开发中,视需求重载各种数据类型,不要重载功能不同的函数。

注意:

  • 使用重载函数时,如果数据类型不匹配,C++尝试使用类型转换与形参进行匹配,如果转换后有多个函数能匹配上,编译将报错。

  • 引用可以作为函数重载的条件,但是,调用重载函数的时候,如果实参是变量,编译器将形参类型的本身和类型引用视为同一特征。

  • 如果重载函数有默认参数,调用函数时,可能导致匹配失败。

  • const不能作为函数重载的特征。

  • 返回值的数据类型不同不能作为函数重载的特征。

C++的名称修饰:编译时,对每个函数名进行加密,替换成不同名的函数。

void MyFunctionFoo(int,float);

void MyFunctionFoo(long,float);

?MyFunctionFoo@@YAXH(int,float);

#void MyFunctionFoo^$@(long,float)

3、内联函数

C++将内联函数的代码组合到程序中,可以提高程序运行的速度。

语法:在函数声明和定义前加上关键字inline。

通常的做法是将函数声明和定义写在一起。

注意:

  • 内联函数节省时间,但消耗内存。

  • 如果函数过大,编译器可能不将其作为内联函数。

  • 内联函数不能递归。

示例:

#include <iostream>         // 包含头文件。
using namespace std;

inline void show(const short bh, const string message)   // 表白函数。
{
	cout << "亲爱的" << bh << "号:" << message << endl;
}

int main()
{
	//show(3, "我是一只傻傻鸟。");
	{
		int bh = 3;
		string message = "我是一只傻傻鸟。";
		cout << "亲爱的" << bh << "号:" << message << endl;
	}
	// show(8, "我有一只小小鸟。");
	{
		int bh = 8;
		string message = "我有一只小小鸟。";
		cout << "亲爱的" << bh << "号:" << message << endl;
	}
	// show(5, "我是一只小小鸟。");
	{
		int bh = 5;
		string message = "我是一只小小鸟。";
		cout << "亲爱的" << bh << "号:" << message << endl;
	}
}

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

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

相关文章

DeepSeek 助力 Vue 开发:打造丝滑的开关切换(Switch)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

使用Python爬虫实时监控行业新闻案例

目录 背景环境准备请求网页数据解析网页数据定时任务综合代码使用代理IP提升稳定性运行截图与完整代码总结 在互联网时代&#xff0c;新闻的实时性和时效性变得尤为重要。很多行业、技术、商业等领域的新闻都可以为公司或者个人发展提供有价值的信息。如果你有一项需求是要实时…

语言大模型基础概念 一(先了解听说过的名词都是什么)

SFT&#xff08;监督微调&#xff09;和RLHF&#xff08;基于人类反馈的强化学习&#xff09;的区别 STF&#xff08;Supervised Fine-Tuning&#xff09;和RLHF&#xff08;Reinforcement Learning from Human Feedback&#xff09;是两种不同的模型训练方法&#xff0c;分别…

DeepSeek v3 技术报告阅读笔记

注 本文参考 DeepSeek-v3 / v2 / v1 Technical Report 及相关参考模型论文本文不包括基础的知识点讲解&#xff0c;为笔记/大纲性质而非教程&#xff0c;建议阅读技术报告原文交流可发送至邮箱 henryhua0721foxmail.com 架构核心 核心&#xff1a; MLA 高效推理DeepSeekMOE 更…

GESP2024年9月认证C++七级( 第三部分编程题(1)小杨寻宝)

参考程序&#xff1a; #include <bits/stdc.h> using namespace std; const int N 1e510; vector<int> g[N]; // 图的邻接表 int col[N], dep[N], has[N];// 深度优先遍历&#xff0c;计算每个节点的深度 void dfs(int x, int fa) {dep[x] dep[fa] 1; // 计算…

解锁电商数据宝藏:淘宝商品详情API实战指南

在电商蓬勃发展的今天&#xff0c;数据已成为驱动业务增长的核心引擎。对于商家、开发者以及数据分析师而言&#xff0c;获取精准、实时的商品数据至关重要。而淘宝&#xff0c;作为国内最大的电商平台&#xff0c;其海量商品数据更是蕴含着巨大的价值。 本文将带你深入探索淘…

webshell通信流量分析

环境安装 Apatche2 php sudo apt install apache2 -y sudo apt install php libapache2-mod-php php-mysql -y echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php sudo ufw allow Apache Full 如果成功访问info.php&#xff0c;则环境安…

在 rtthread中,rt_list_entry (rt_container_of) 已知结构体成员的地址,反推出结构体的首地址

rt_list_entry (rt_container_of)宏定义&#xff1a; /*** rt_container_of - return the start address of struct type, while ptr is the* member of struct type.*/ #define rt_container_of(ptr, type, member) \((type *)((char *)(ptr) - (unsigned long)(&((type *…

趣味魔法项目 LinuxPDF —— 在 PDF 中启动一个 Linux 操作系统

最近&#xff0c;一位开源爱好者开发了一个LinuxPDF 项目&#xff08;ading2210/linuxpdf: Linux running inside a PDF file via a RISC-V emulator&#xff09;&#xff0c;它的核心功能是在一个 PDF 文件中启动并运行 Linux 操作系统。它通过巧妙地使用 PDF 文件格式中的 Ja…

【Linux】Socket编程—TCP

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;Linux系统编程 这里将会不定期更新有关Linux的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目…

新数据结构(9)——Java异常体系

异常的种类 程序本身通常无法主动捕获并处理错误&#xff08;Error&#xff09;&#xff0c;因为这些错误通常表示系统级的严重问题&#xff0c;但程序可以捕获并处理异常&#xff08;Excrption&#xff09;&#xff0c;而Error则被视为一种程序无法或不应尝试恢复的异常类型。…

NixHomepage - 简单的个人网站

&#x1f4bb; NixHomepage - 简单的个人网站 推荐下个人的开源项目&#xff0c;演示网站&#xff0c;项目链接 https://github.com/nixgnauhcuy/NixHomepage&#xff0c;喜欢的话可以为我的项目点个 Star~ &#x1f4f7; 预览 ⚙️ 功能特性 多平台适配 明亮/暗黑模式切换 W…

HCIA项目实践---OSPF的知识和原理总结

9.5 OSPF 9.5.1 从哪些角度评判一个动态路由协议的好坏&#xff1f; &#xff08;1&#xff09;选路佳&#xff08;是否会出环&#xff09; OSPF 协议采用链路状态算法&#xff0c;通过收集网络拓扑信息来计算最短路径&#xff0c;从根本上避免了路由环路的产生。 &#xff08…

Calico网络组件本地部署支持IPv6(Kubernetes)

知其然 问题背景 因项目现场的网络正逐步从IPv4向IPv6迁移&#xff0c;这几年现场服务器基本上都配置了双栈&#xff1b;但随着IPv6铺开&#xff0c;出现了很多纯IPv6的服务器&#xff0c;并且要求通信优先使用IPv6。 在项目建设之初&#xff0c;其实就考虑了上述情况&#…

【广州大学主办,发表有保障 | IEEE出版,稳定EI检索,往届见刊后快至1个月检索】第二届电气技术与自动化工程国际学术会议 (ETAE 2025)

第二届电气技术与自动化工程国际学术会议 (ETAE 2025) The 2nd International Conference on Electrical Technology and Automation Engineering 大会官网&#xff1a;http://www.icetae.com/【更多详情】 会议时间&#xff1a;2025年4月25-27日 会议地点&#xff1a…

Python项目31:待办事项列表应用1.0(命令行界面+Json+类+初学者必做)

------------★Python练手项目源码★------------ Python项目27&#xff1a;用Tkinter写日志管理系统&#xff08;中下等难度&#xff09; Python项目26&#xff1a;设计学生成绩管理系统&#xff08;简易版&#xff09; Python项目25&#xff1a;带滚动效果的商场抽奖系统&…

Redis 01 02章——入门概述与安装配置

一、入门概述 &#xff08;1&#xff09;是什么 Redis&#xff1a;REmote Dictionary Server&#xff08;远程字典服务器&#xff09;官网解释&#xff1a;Remote Dictionary Server(远程字典服务)是完全开源的&#xff0c;使用ANSIC语言编写遵守BSD协议&#xff0c;是一个高…

Large Language Model Distilling Medication Recommendation Model

摘要&#xff1a;药物推荐是智能医疗系统的一个重要方面&#xff0c;因为它涉及根据患者的特定健康需求开具最合适的药物。不幸的是&#xff0c;目前使用的许多复杂模型往往忽视医疗数据的细微语义&#xff0c;而仅仅严重依赖于标识信息。此外&#xff0c;这些模型在处理首次就…

2025最新版Node.js下载安装~保姆级教程

1. node中文官网地址&#xff1a;http://nodejs.cn/download/ 2.打开node官网下载压缩包&#xff1a; 根据操作系统不同选择不同版本&#xff08;win7系统建议安装v12.x&#xff09; 我这里选择最新版win 64位 3.安装node ①点击对话框中的“Next”&#xff0c;勾选同意后点…

springboot如何将lib和jar分离

遇到一个问题&#xff0c;就是每次maven package或者maven install后target中的jar很大&#xff0c;少的50几MB&#xff0c;大的100多兆 优化前&#xff1a; 优化后&#xff1a; 优化前 优化后压缩率77.2MB4.65MB93% 具体方案&#xff1a; pom.xml中 <build><…