杀杀杀杀杀杀杀杀杀

在这里插入图片描述

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。


C语言标准定义的32个关键字

    • 1. 数据类型关键字(12个)
      • (1) 声明和定义的区别
      • (2) 数据类型关键字
    • 2. 控制语句关键字(12个)
    • 3. 存储类关键字(5个)
    • 4. 其他关键字(3个)


专栏:《精通C语言》


1. 数据类型关键字(12个)

C语言中的数据类型主要有下面几种。实际上,数据类型可以理解为固定大小内存块的别名,给变量指定类型就是告诉编译器给该变量分配多大的内存空间,而变量相当于是内存块的门牌号。

在这里插入图片描述

(1) 声明和定义的区别

定义可以看作是声明的一个特例,并非所有的声明都是定义。可以通过是否分配内存来区分定义和声明,定义会建立存储空间,而声名不会建立存储空间。

int function()
{
    //定义
    int val; //定义一个变量val,此时会给val分配内存,由数据类型int决定分配多大内存,int为4字节。
    val = 10; //可以为val赋值。
    
    //声明
	extern int val_2; //声明变量val_2,不会建立内存。
    //val_2 = 10; //error: 声明不会建立内存,没有内存空间所以无法赋值。
    
    return 0;
}
  • 定义:定义是指创建一个对象并为这个对象分配一块内存,同时将变量名和这个内存块进行绑定。但是,同一个变量在同一作用域只能定义一次,如果多次定义的话,编译器会提示重定义错误。
  • 声明:
    • 告诉编译器,某个名称已经被预定了,其他对象/内存块不能再使用这个名称。
    • 告诉编译器,某个名称已经绑定好内存块了,该对象是在其他位置定义的,这里用到本名称时不要报错。

(2) 数据类型关键字

char:声明字符型变量。

char类型用于存储一个单一字符,即1字节存储单元。在给char类型变量赋值时需要把值用英文半角单引号’'引起来,存储时并非真正把该字符放到存储空间,而是把该字符对应的ASCII码存放到存储单元中。(也可以把char类型看作是1字节整形)。

ASCII对照表如下

ASCII值控制字符ASCII值字符ASCII值字符ASCII值字符
0NUT32(space)64@96
1SOH33!65A97a
2STX34"66B98b
3ETX35#67C99c
4EOT36$68D100d
5ENQ37%69E101e
6ACK38&70F102f
7BEL39,71G103g
8BS40(72H104h
9HT41)73I105i
10LF42*74J106j
11VT43+75K107k
12FF44,76L108l
13CR45-77M109m
14SO46.78N110n
15SI47/79O111o
16DLE48080P112p
17DCI49181Q113q
18DC250282R114r
19DC351383S115s
20DC452484T116t
21NAK53585U117u
22SYN54686V118v
23TB55787W119w
24CAN56888X120x
25EM57989Y121y
26SUB58:90Z122z
27ESC59;91[123{
28FS60<92/124|
29GS61=93]125}
30RS62>94^126`
31US63?95_127DEL

在上面的ASCII码表中,ASCII值0-31表示非打印控制字符,用于控制打印机等外围设备;32-126为打印字符,这些字符在键盘上都可以找到;127表示del命令。

转义字符

转义字符含义ASCII码值(十进制)
\a警报007
\b退格(BS) ,将当前位置移到前一列008
\f换页(FF),将当前位置移到下页开头012
\n换行(LF) ,将当前位置移到下一行开头010
\r回车(CR) ,将当前位置移到本行开头013
\t水平制表(HT) (跳到下一个TAB位置)009
\v垂直制表(VT)011
\代表一个反斜线字符""092
代表一个单引号(撇号)字符039
"代表一个双引号字符034
?代表一个问号063
\0数字0000
\ddd8进制转义字符,d范围0~73位8进制
\xhh16进制转义字符,h范围09,af,A~F3位16进制

int:声明整型变量。

在C语言标准中并没有明确规定整型数据的长度,整型数据在内存中所占的字节数与操作系统有关系。(一般为4字节)

打印格式含义
%d输出一个有符号的10进制int类型
%o输出8进制的int类型
%x输出16进制的int类型,字母以小写输出
%X输出16进制的int类型,字母以大写写输出
%u输出一个10进制的无符号数

short:声明短整型变量。

长度一般不长于int型数据。(一般为2字节)

long:声明长整型变量。

长度一般不短于int型数据。(Windows为4字节;Linux为4字节(32位),8字节(64位)。)

打印格式含义
%hd输出short类型
%d输出int类型
%l输出long类型
%ll输出long long类型
%hu输出unsigned short类型
%u输出unsigned int类型
%lu输出unsigned long类型
%llu输出unsigned long long类型

float:声明单精度浮点型变量。

浮点型变量也叫做实型变量,用于存储小数数值。float单精度浮点型一般占用4字节存储空间,7位有效数字。

double:声明双精度浮点型变量。

double双精度浮点型精度高于float单精度浮点型,占用8字节存储空间,15-16位有效数字。

浮点型变量存储的是小数,并且浮点型变量的存储单元是有限的,这就导致一个小数有效位以外的数字将被舍去,这样便会出现一些误差。尤其是float单精度浮点型,有时候将一个小数赋值给一个float型变量,然后打印该浮点型变量都会出现和原小数不一致这样的情况。一般使用double双精度可以提升精度,并且在C语言中,一个小数后面不加f则被认为是双精度double类型,只有小数后面加f才表示float类型,比如3.14f。

signed:声明有符号类型变量。

缺省时,编译器默认为signed有符号类型。在计算机中,所有的数据都是以01的二进制形式来存储的,对于有符号数来说如何表示一个数值的正负是一个问题,因此便有了原码、反码和补码。

  • 原码:二进制数据的最高位用来作为符号位,1表示负数,0表示正数,剩余位来表示这个数据的数值大小(绝对值),也就是说,负数的原码是在其绝对值原码的基础上将最高位变成0。原码的表示简单易懂,正负数区分方便且易于转换,但是在实际用于计算时却不太方便,当两个正数做减法运算,或者两个异号的数相加时,必须先比较两个数的绝对值大小才能进行减法运算,以便于决定最终结果是正号还是负号。所以,原码表示数据时不便于做加减运算。
  • 反码:正数的反码与原码相同;负数的反码是在负数的原码基础上,符号位不变,其它位全部取反。反码的存在一般是为了方便计算补码。
  • 补码:对正数来说,原码、反码、补码是完全一致的;对负数来说,补码是在其反码的基础上将整个数加1。在计算机系统中,所有的数值一律用补码的形式来存储。补码的存在主要有这几种意义:
    • 统一0的编码。不管是用原码还是反码来表示0,都会有两种表示方式,即正0和负0,但是我们知道,0不区分正负。这就导致同一个数值0出现两种表示方式,而使用补码表示时,对于正0,原码为00000000,反码为00000000,补码为00000000;对于负0,原码为10000000,反码为11111111,补码为11111111+1=00000000,其中最高位(第九位)数字1被舍弃。这样,正0和负0的补码就一样了。
    • 便于运算。使用补码进行运算时可以将减法转化为加法,对于任何数的加减运算,都直接使用补码进行加法运算即可,并且可以将符号位和其他位统一处理,当两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位直接舍弃。

unsigned:声明无符号类型变量。

数据类型占用空间取值范围
short2字节-32768 到 32767 (-2^15 ~ 2^15-1)
int4字节-2147483648 到 2147483647 (-2^31 ~ 2^31-1)
long4字节-2147483648 到 2147483647 (-2^31 ~ 2^31-1)
unsigned short2字节0 到 65535 (0 ~ 2^16-1)
unsigned int4字节0 到 4294967295 (0 ~ 2^32-1)
unsigned long4字节0 到 4294967295 (0 ~ 2^32-1)

struct:声明结构体变量。

数组是相同类型数据的集合,而结构体可以把不同的数据组合成一个整体。通过结构体,我们可以把大量的不同类型数据,甚至是函数和其他复合类型数据打包为一个整体。在使用struct关键字时,应区分开结构体类型和结构体变量的区别,声明结构体类型并不会分配内存,只有在定义结构体类型的时候才会分配内存。通常struct关键字会和typedef关键字一块使用,通过别名的方式可以在定义结构体变量时不需要再写struct关键字。

struct st
{
    int a;
    char b;
}; //声明结构体类型
struct st s_val = {1, 'a'}; //定义结构体变量,分配内存
							//定义结构体变量时不能省略struct关键字

typedef struct st
{
    int a;
    char b;
}_st; //给结构体类型取别名为_st
_st val = {1, 'a'}; //可以不写struct

结构体变量所占的存储空间大小是所有结构体成员所占存储空间大小的总和,并且需要考虑内存对齐方式。而且,空结构体(没有任何成员)也是占存储空间的,空结构体占1字节存储空间。

在结构体中可以包含一种称为柔性数组的成员,柔性数组是一个未知大小的数组,它必须是结构体的最后一个成员,并且柔性数组成员的前面必须有一个其他成员。

struct st
{
    int val;
    int arr[0]; //int arr[];
};

这个0长度的数组成员arr是不占存储空间的,这个结构体的大小为4字节。有了这个0长度数组我们便可以方便的扩展这个结构体的大小了

struct st *p_st = (struct st *)malloc(sizeof(struct st) + 10 * sizeof(int));

如上,我们使用包含0长度数组的结构体类型定义一个结构体指针,并通过malloc在堆上为其分配一块内存,这块内存的大小为44字节,而结构体类型大小只有4字节,但是我们却可以像访问普通数组一样通过p_st[i]来访问这块内存。也就是说,柔性数组并不是结构体类型的成员,但是通过结构体成员却可以访问我们自定义的柔性数组存储空间。

最后,在C++中,struct结构体和class类的区别,struct成员默认是public属性,而class的成员默认是private属性。

同样,在C语言中也可以实现C++面向对象的效果,使用struct结构可以实现封装,而结构体做结构体成员又可以实现C++中的继承,并且,函数指针做结构体成员可是模仿C++类中的方法。

union:声明联合数据类型。

联合union是一个能在同一个存储空间存储不同类型数据的类型,也就是说,union的所有成员共享同一块存储空间,同一存储空间段可以用来存放几种不同类型的成员,但每一时刻只有一种起作用。联合体所占的存储空间长度为占用存储空间最大的成员的长度,所以也叫做共用体。共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员的值会被覆盖。并且,共用体变量的地址和它的各成员的地址都是同一地址。

一个union变量只分配一个足够大的存储空间能够存储最大长度的成员,而不会给每一个成员都分配内存,这是union与struct最大的区别。union主要用来达到节省空间的目的,和struct一样,在C++中,union的成员默认属性为public。

看下面的例子

typedef union
{
	int data;
	char buf[2];
}u_t;

int main()
{
	u_t* p, u;
	memset(&u, 0, sizeof(u));
	p = &u;
	p->buf[0] = 0x12;
	p->buf[1] = 0x34;

	printf("%x\n", p->data);

	return 0;
}

对union成员的访问也需要考虑大端存储模式和小端存储模式。

enum:声明枚举类型。

通过enum枚举类型可以定义枚举变量,该枚举变量的值只能是枚举类型中列举出来的那些值。

enum  枚举名
{
	枚举值表
};

枚举值表中的所有可用值是枚举变量可以使用的值,也成为枚举元素。枚举值是常量,在程序中枚举值不能作为左值(不能给枚举值使用赋值语句赋值)。另外,枚举元素本身由系统定义了一个表示序号的数值从0开始顺序定义为0,1,2 …依次递增,我们也可以显示的给枚举元素赋值。

enum day
{
	mom = 1,
    tue,	//2
    wed,	//3
    fri = 5,
    sat,	//6
    sun		//7
};

我们知道使用宏定义#define也可以定义常量,但是宏定义常量和枚举常量是有区别的,#define 宏常量是在预编译阶段进行简单替换,而枚举常量则是在编译的时候确定其值。

void:声明空类型指针(void类型指针可以接受任何类型指针的赋值,无需类型转换),声明函数无返回值或无参数等。

void主要的用途是限制函数的返回值或者函数参数。在C语言中,如果一个函数不加返回值类型限定,那么编译器会默认该函数返回整型值,所以,当一个函数没有返回值的时候,一定要声明为void类型。当函数没有参数时,也应该声明为void。实际上,在C++中函数参数为void表示该函数不接受任何参数,如果调用该函数时添加了参数那么会报错;而C语言中,参数为void的函数可以接受任何类型的参数。为了统一,无论C还是C++,只要函数没有参数,都要显式指明参数为void。

void类型指针可以指向任何类型的内存块,但是使用void类型指针的时候要格外注意。在ANSI标准中,不允许对void类型指针进行加减操作,这是因为指针的步长是由指针的类型决定的。比如

int *p = 0xaa;
p++; //指针类型为int,每次加一移动4字节

这里int类型的指针每次自加一会移动4字节,因为int类型的对象占据的存储空间就是4字节。而void类型的指针在移动时你并不知道它指向的存储空间的大小。但是在GNU标准中是允许对void类型指针进行加减操作的。为了统一,我们可以在对void类型指针进行加减操作时强制类型转换,以此来说明指针移动步长。

void *p;
(int *)p++;

对于函数来说,如果函数的参数可以是任意类型指针,那么可以将函数参数声明为void*类型,比如典型的C语言内存操作函数memset和memcpy函数,内存操作函数所操作的对象是一块内存本身,本就不应该关心这块内存是什么类型,只要我们通过函数参数告诉编译器我们要操作的这块内存的大小就行了,这也是C语言内存操作函数的精髓所在,并且也体现了作为一个内存操作API的统一性。比如

int buf[20];
memset(&buf, 0, 20 * (sizeof(int)));

这句代码的意思是把buf这个数组清0,我们只要把buf这块内存的首地址传给memset函数,并将要清0的这块内存的大小通过参数传入就可以了。

最后,void是一种抽象,可以参考C++中的抽象类来理解。抽象类不能实例化,同样我们也不能去定义一个void类型的变量,因为在定义变量时,编译器要为变量分配内存,而void类型本身就是一种抽象,编译器不知道分配多大内存给这个变量。通常,void类型用于定义一个可以指向任何类型内存块的指针。

2. 控制语句关键字(12个)

if:条件语句。

else:条件语句中的否定分支,在if后使用或作为else if分支。

switch:开关语句。

case:开关语句分支。

case后面的值只能是整型或字符型的常量或者常量表达式。当有较多的case选项时,应该尽量把出现概率更大的case选项放在前面,以提升程序的执行效率。

default:开关语句中的其他分支。

for:循环语句。

do:循环语句中的循环体。

while:循环语句中的条件。

break:跳出循环。

continue:跳出本次循环,进入下一次循环。

goto:无条件跳转。

return:返回语句,可带参数。

return用来终止一个函数,并将return后面的值返回给函数的返回值。在函数内部,当执行到return语句的时候就会终止这个函数,并返回值,return语句后面的程序将不会再被执行。

return返回的值不能是存储在栈上的值(局部变量),因为局部变量在这个函数结束的时候被自动销毁,它的生命周期仅限于这个函数内部,所以不能作为return语句的返回值。

3. 存储类关键字(5个)

auto:声明自动变量,缺省时编译器默认为auto。

默认情况下,缺省时所有变量都是auto的。

extern:声明外部变量。

extern表示外部的,通过extern声明的变量或函数表示该变量或者函数是在外部文件定义的,告诉编译器在本文件中遇到该变量或者函数时,去其他文件中寻找变量或函数的定义。

register:声明寄存器变量。

定义寄存器变量,提高效率。register是建议型的指令,而不是命令型的指令,如果CPU有空闲寄存器,那么register就生效,如果没有空闲寄存器,那么register无效。该关键字请求编译器尽量的将变量存放在CPU内部寄存器中,这样在访问变量时不需要再通过内存寻址的方式访问,而是直接在寄存器中访问,大大提升了访问速度。但是CPU内部寄存器是有限的,所以register关键字只能是尽可能的请求编译器把变量存放在寄存器,而不是一定存放在寄存器。因为register关键字用于请求将数据存放在寄存器,所以使用register修饰符来修饰的变量必须是能被CPU寄存器所接受的类型,即register修饰的变量必须是长度小于或等于整形长度的值。同时,因为register修饰的变量可能会存放在寄存器中(也可能存放在内存中),所以不能对register修饰的变量进行取址操作,即不能通过取址操作符&来获取register修饰变量的地址。

static:声明静态变量。

  • 修饰变量

    static关键字可以修饰全局变量和局部变量,并且他们都会被存放在内存的静态区。

    • 静态全局变量:限定变量的作用域为当前文件,即从变量定义之处开始一直到当前文件末尾,当前文件中该变量定义之前也无法使用(除非加extern声明),其他文件中即便是使用extern声明也无法使用。
    • 静态局部变量:定义在函数体内部,并且作用域仅限于当前函数,当前文件该函数体外部无法使用。因为static修饰的静态变量存放在内存的静态区,所以函数运行结束这个静态变量也不会被销毁,函数下次被调用时这个变量的值依然存在,也就是我们说的静态局部变量只能被初始化一次,并且有记忆功能,下次调用函数时可以使用上次函数调用结束时静态局部变量的值。需要注意的是,普通的局部变量存放在栈区,函数调用结束变量就会被析构,也就是说普通局部变量的声明周期为定义该变量的函数体内。而静态局部变量存放在静态区,它的生命周期是整个程序执行期间,也就是说定义该静态局部变量的函数执行完毕,并不会析构静态局部变量,而是在当前程序执行完毕才会析构。
  • 修饰函数

    使用static关键字修饰函数可以将函数变为静态函数,也成为内部函数,静态函数的作用域为当前文件,在该文件之外无法访问。使用静态函数的好处是可以避免不同文件中函数同名引起的错误,但是会导致该文件之外无法调用的问题。

const:声明只读变量(C和C++区别)。

在C语言中,const定义的并不是真正的常量,而是具有只读属性的变量,其本质还是变量,只不过不可修改(实际上在C语言中是可以通过指针等其他方式间接修改的);而在C++中,const定义的是真正的常量,C++中是通过符号表一一对应的方式实现的。通过下面的例子也可以证明

const int NUM = 10;
char buf[NUM];

上面代码在C语言中编译不通过,但是在C++中编译通过。我们知道,定义数组时要指定数组大小,以便于编译器分配内存。在C语言中编译不通过也就证明了const定义的依然是变量,而不是常量。

编译器通常不会为const只读变量分配存储空间,而是将它们保存在符号表中,这使得它们成为一个编译期间的值,没有读写内存的操作,大大提高了效率。另外需要注意const与宏#define的区别

#define NUM 1 		//宏定义一个常量
const int VAL = 2; 	//还没有将VAL放入内存中
int a = VAL; //此时为VAL分配内存,后面不再分配内存
int b = NUM; //预编译期间进行宏替换,分配内存
int c = VAL; //不会分配内存
int d = NUM; //宏替换,还会分配内存

从汇编的角度来看,const定义的只读变量只是给出了内存地址,而#define给出的是立即数。所以,在程序运行过程中,const定义的只读变量只有一份拷贝(全局只读变量存放在静态区,而不是堆栈),而#define定义的常量在内存中有多份拷贝。#define在预编译的时候进行宏替换,而const只读变量是在编译时确定它的值。另外,#define定义的常量没有类型,而const修饰的只读变量是有类型的。const 修饰的只读变量不能用来作为定义数组的维数,
也不能放在case 关键字后面。

最后,当const修饰指针时,放在不同位置所代表的含义也不同。

const int *p;			//const修饰指针指向的内存,
						//指针本身可变,指针指向的内存不可修改
int const *p;			//const修饰指针指向的内存,
						//指针本身可变,指针指向的内存不可修改

int * const p;			//const修饰指针本身,
						//指针指向不可修改,指针指向的内存可以修改

const int const *p;		//指针本身和指针指向的内存都不可修改

4. 其他关键字(3个)

sizeof:计算一个对象所占的字节数。

sizeof在使用时虽然会加括号,但是他并不是函数,而是一个关键字。实际上,通过sizeof计算一个变量所占的内存大小时可以省略括号,sizeof(val)和sizeof val都可以,但是在计算数据类型的大小时必须加括号sizeof(int),否则的话会和类型扩展混淆,比如unsigned int就是扩展为无符号整型变量。因为sizeof不是函数,所以在使用时不需要包含任何头文件,但是sizeof是有返回值的,范围值类型为size_t,在32位操作系统下是unsigned int类型。

在计算一个字符串变量的大小时要区分sizeof与strlen的区别,strlen是一个函数,用于计算字符串的长度,所以不包含字符串最后的’\n’,而sizeof是计算变量所占内存大小,包括字符串结束符’\n’。

typedef:取别名。

typedef可以为一个数据类型定义一个新的名字,但是不能创建一个新的类型。与#define不同,typedef仅限于为数据类型取别名,而不能为表达式或具体的值取别名。#define发生在预处理阶段,typedef发生在编译阶段。

volatile:防止编译器优化,说明变量在程序执行中可被隐含地改变。

volatile是易变的意思,它修饰的变量表示该变量的值可能被某些因素所修改,比如操作系统、硬件外设或其他线程等等。volatile关键字修饰的变量,编译器不会对改变量进行优化访问。

当我们读取一个普通变量的值时,编译器为了加快访问速度,一般会在缓存中读取该变量的值,而不是直接去寄存器取值。但是,有时候寄存器的值并不是通过程序去修改的,比如嵌入式开发中常用开发板进行开发,很多时候寄存器的值会被芯片的外设所修改。这时候,虽然我们程序中并没有去修改寄存器的值,但是寄存器值却因为外界因素而发生了改变。当我们去访问这种变量的时候,如果不加volatile关键字,编译器默认会在缓存中取值,而此时缓存中的值是一个旧值,变量的真实值已经发生了改变。所以,加volatile关键字就是为了告诉编译器,不要对访问进行优化,每次都应该去变量的地址处去访问变量值,以此来确保每次取到的都是变量的最新值。

下面通过例子说明

int val = 1;
int a = val;
int b = val;

在上面的代码中,变量val没有被用作左值(也就是说在程序中变量val的值没有被显式改变),这时候编译器就会认为变量val的值没有发生过改变,并会对val的访问做优化处理。当给变量a赋值时,编译器取到val的值之后赋给a,并且这个值会被放到缓存中。当给b赋值时,因为编译器认为val的值没有发生改变,所以会直接在缓存中取val的值,而不会去val变量的地址处取值,这样大大提高了访问速度。这么做的前提是,两次访问val的语句之间没有将val当左值的语句(即修改val值的语句)。

如果说将val变量修饰为volatile变量,那就不同了。

volatile int val = 1;
int a = val;
int b = val;

此时,编译器认为val的值是随时可能发生改变的,不管程序中有没有将val当作左值的语句,每次访问val变量都会区val变量的地址处去访问。也就是说,在给a赋值时,编译器将会在val地址处取值,当给b赋值时,编译器依然会去val变量的地址处取值。

一般来说,对寄存器变量、端口数据变量、多线程共享数据变量使用volatile修饰可以保证对变量真实值的稳定访问。


在这里插入图片描述
在这里插入图片描述


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GRFB-UNet:一种新的多尺度注意力网络,用于铺路分割

不同场景下的带注释的触觉铺装示例: GRFB-UNet网络结构: GRFB模块的结构: 铺路在视障人士的旅行中起着至关重要的作用。因此,识别铺装的形状和位置以支持视障人士的移动性是相当有意义的,而视觉分割技术就适合这项任务。为了有效提高触觉铺装分割的精度和鲁棒性,…

Netty核心组件介绍

Netty是一款用于创建高性能网络应用程序的高级框架。Netty的核心组件如下&#xff1a; Channel回调Future事件和ChannelHander Channel channel是Java NIO的一个基本构造。可以把Channel看作是传入或传出数据的载体。它可以被打开或关闭&#xff0c;连接或断开连接。 回调 …

揭秘抖音快速涨10000有效粉的方法——巨量千川投流打造真实粉丝快速增长

随着短视频平台的流行&#xff0c;越来越多的用户开始在抖音上展示自己的才艺和生活。然而&#xff0c;在这个庞大的用户群体中如何迅速地涨粉成为了抖友们普遍关注的问题。今天&#xff0c;我们将揭秘一种被全网搜索的抖音快速涨粉方法——巨量千川投流&#xff0c;官方真实流…

揭秘!你的电商产品为何滞销?同行火爆销售的7大原因!

同样做电商&#xff0c;但自家产品销量不如竞对同行&#xff0c;可能的原因有多种&#xff0c;以下是店雷达总结7个可能的原因和对策&#xff1a; 一、市场竞争分析不足 未能准确识别并分析竞争对手的产品、定价、营销策略等关键信息&#xff0c;导致自身产品无法脱颖而出。 …

深度解析YOLOV9,目标检测算法(附论文和源码)|

目录 一、YOLOV9 1、概述&#xff1a; 2&#xff0c;论文摘要&#xff1a; 输入数据在前馈过程中可能会有不可忽略的信息丢失。这种信息丢失会导致梯度流出现偏差&#xff0c;而梯度流又被用于更新模型。上述问题会导致深度网络在目标和输入之间建立不正确的关联&#xff0c…

算法分析与设计复习__递归方程与分治

总结自&#xff1a;【算法设计与分析】期末考试突击课_哔哩哔哩_bilibili 1.递归&#xff0c;递归方程 1.1递归条件: 1.一个问题的解可以分解为几个子问题的解&#xff1b; 2.这个问题与分解之后的子问题&#xff0c;除了数据规模不同&#xff0c;求解思路完全一样; 3.存在…

【Git教程】(十八)拆分大项目 — 概述及使用要求,执行过程及其实现,替代解决方案 ~

Git教程 拆分大项目 1️⃣ 概述2️⃣ 使用要求3️⃣ 执行过程及其实现3.1 拆分模块版本库3.2 将拆分出的模块作为外部版本库集成 4️⃣ 替代解决方案 通常软件项目都是由单体小型系统开始的&#xff0c;在开发过程中项目规模和团队人员不断扩大&#xff0c; 将项目模块化会显得…

Redis-持久化操作-AOF

持久化操作-AOF AOF是什么&#xff1f; 以日志的形式来记录每个写操作&#xff0c;将Redis执行过的所有写指令记录下来&#xff08;读操作不记录&#xff09;&#xff0c;只允许加文 件但不可以改写文件&#xff0c;redis启动之初会读取该文件重新构建数据&#xff0c;换言之…

git入门操作

一、介绍 Git是一个开源的分布式版本控制系统&#xff0c;由Linus Torvalds创建&#xff0c;用于有效、高速地处理从小到大的项目版本管理。 二、注册Git代码托管平台账号 以下几个平台可供选择&#xff1a; Gitee: https://gitee.com/(国内) Gitee&#xff08;码云&…

从丢失到找回:手机相册恢复实战教程

“之前因为手机延迟把三千多张相片都删了&#xff0c;花了几个小时找文档&#xff0c;最后也没找到。对于爱拍照的朋友来说&#xff0c;照片被误删或不见真的会超级难过&#xff01;请问大家有什么好方法能够恢复照片吗&#xff1f;” 在数字时代&#xff0c;手机相册成为了我…

PLC的ST语言实现IIR butterworth低通滤波器

参考 Butterworth Filter Design in C – The Code Hound matlab代码&#xff0c;创建一个fc0.1的4阶butterworth低通滤波器。 format long[b,a] butter(4,0.1,low)input1 [1,2,3,1,2,3,1,2,3,0,0]; output filter(b,a,input1)过滤input1的结果为 output Columns 1 throu…

嵌入式基础课程配套电机FOC伺服电机开发板AT32F403磁编码IMU姿态

嵌入式基础课程配套电机FOC伺服电机开发板AT32F403磁编码IMU姿态 带你入门嵌入式有二十多年开发经验的老技骨做技术支持整个开发包硬件包括电机2205&#xff0c;支持12V到24V宽输入&#xff0c;配套12V2A电源。包装原理图和PCB嵌入式软件嵌入式基础课程 带你入门嵌入式 电机FO…

免费SSL证书怎么签发

大家都知道SSL证书好&#xff0c;作用大&#xff0c;安全性高&#xff0c;能加权重&#xff0c;等保必须的参考值。但是如何选择合适且正确的证书也是至关重要的&#xff0c;网站更适合单域名证书、多域名证书、泛域名证书、还是多域名通配符证书。 首先大家要清楚&#xff0c…

MATLAB车辆动力学建模 ——《控制系统现代开发技术》

引言 在上这门课之前&#xff0c;我已经用过CasADi 去做过最优化的相关实践&#xff0c;其中每一步迭代主要就是由&#xff1a;对象系统优化求解两部分组成的。这里我们重点介绍 “对象系统”如何去描述 &#xff0c;因为它是每一步迭代中重要的一环——“优化求解”会获得控制…

Java逐层解析JSON的内存占用分析

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 在当今的软件开发世界中&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;已经成为了数据传输和存储的事实标准。由于其轻量级且易于人类阅读的特点&#xff0c;JSON被广泛用于Web服务、移动应用…

【制作100个unity游戏之26】unity2d横版卷轴动作类游戏5(附带项目源码)

最终效果 系列导航 文章目录 最终效果系列导航前言三段攻击攻击设置只对敌人造成伤害限制可以移动攻击问题 角色连续按四下攻击&#xff0c;最后会多a一下问题&#xff1a;站在原地连续攻击野猪&#xff0c;只有第一下攻击野猪才掉血&#xff0c;后面的攻击野猪不掉血源码完结 …

一图流解释Java中线程状态的转换

目录 一.Java中的几大线程状态 二.线程之间的相互转换 ▐ NEW --> RUNNABLE ▐ RUNNABLE <--> WAITING ▐ RUNNABLE <--> Timed Waiting ▐ RUNNABLE<--> BLOCKED ▐ RUNNABLE<-->TERMINATED 一.Java中的几大线程状态 简单来说线程可以处于…

美团小程序mtgsig1.2逆向

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872 本文章未…

网络安全等级保护在工业控制系统中的应用

工业控制系统(Industrial Control Systems,ICS)&#xff0c;是由各种自动化控制组件和实时数据采集、监测的过程控制组件共同构成。其组件包括数据采集与监控系统(SCADA)、分布式控制系统(DCS)、可编程逻辑控制器(PLC)、远程终端(RTU)、智能电子设备(IED)&#xff0c;以及确保各…

C语言单向链表、双向链表和循环链表有什么区别?

一、问题 链表分为单向链表、双向链表和循环链表&#xff0c;它们的不同之处是什么呢&#xff1f; 二、解答 &#xff08;1&#xff09;单向链表。 所谓单向链表&#xff0c;就是指数据结点是单向排列的。⼀个单向链表结点由两个域组成&#xff0c;存储在结构体类型中。⼀个域…