C语言之操作符
目录
1. 操作符的分类
2. 移位操作符
2.1 左移操作符 <<
2.2 右移操作符 >>
3. 位操作符
3.1 按位与 &
3.2 按位或 |
3.3 按位异或 ^
3.4 按位取反 ~
3.5 例题
3.5.1 按位异或 ^ 拓展公式
3.5.2 不能创建临时变量(第三个变量),实现两个整数的交换。
3.5.3 编写代码实现:求⼀个整数n存储在内存中的二进制中1的个数。
3.5.4 整数内存二进制位置1或置0
4. 逗号表达式
5. 下标引用[ ]和函数调用 ()
5.1 下标引用操作符[ ]
5.2 函数调用操作符 ()
6. 结构成员访问操作符 . ->
6.1 结构体
6.1.1 结构体的声明
6.1.2 结构体变量的定义和初始化
6.2 结构成员访问操作符
6.2.1 结构成员的直接访问
6.2.2 结构体成员的间接访问
7. 操作符的属性:优先级、结合性
7.1 优先级
7.2 结合性
8. 表达式求值
8.1 整型提升
8.2 算数转换
8.3 总结
1. 操作符的分类
- 算术操作符:+ ,- ,* ,/ ,%
- 移位操作符:<< ,>>
- 位操作符:& ,| ,^
- 赋值操作符:= ,+= ,-= ,*= ,/= ,%= ,<<= ,>>= ,&= ,|= ,^=
- 单目操作符:!,++ ,-- ,&(取地址符), *(指针) , ~ ,+(正号) ,-(负号) , sizeof
- 逻辑操作符:&& ,|| ,!
- 条件操作符:?,:
- 逗号操作符:,
- 下标引用:[ ]
- 函数调用:( )
- 结构成员访问:. ` ->
2. 移位操作符
移位操作符的操作数只能是整数,操作对象是整数在内存中存储的二进制补码,移位的是二进制位。
2.1 左移操作符 <<
移位规则:左边抛弃,右边补0
#include <stdio.h>
int main()
{int a = 5;int b = a << 1;printf("%d\n", a);printf("%d\n", b);return 0;
}
a的值经过左移1位,a的值不变,把左移1位的值赋给b,此时a=5 ,b=10。
2.2 右移操作符 >>
移位规则:右移运算分为两种:
1.逻辑右移:右边抛弃,左边补0
2.算数右移:右边抛弃,左边用原来的值的符号位填充
#include <stdio.h>
int main()
{int a = -5;int b = a >> 1;printf("%d\n", a);printf("%d\n", b);return 0;
}
a的值经过右移1位,a的值不变,把右移1位的值赋给b,此时a=-5 ,b=-3。
大多数编译器都是算术右移。
对于移位运算符,不要移动负数位,这个是标准未定义的。
3. 位操作符
移位操作符的操作数只能是整数,操作对象是整数在内存中存储的二进制补码。
#include <stdio.h>
int main()
{int a = 3;int b = -5;printf("%d\n", a & b);printf("%d\n", a | b);printf("%d\n", a ^ b);return 0;
}
下面是a和b的原码,反码和补码。
3.1 按位与 &
运算规则:两个整数& ,内存中的补码对应的二进制位进行&,有0为0,全1为1。
a & b = 3
3.2 按位或 |
运算规则:两个整数| ,内存中的补码对应的二进制位进行|,有1为1,全0为0。
a | b = -5
3.3 按位异或 ^
运算规则:两个整数^ ,内存中的补码对应的二进制位进行^,相同为0,不同为1。
a ^ b = -8
3.4 按位取反 ~
运算规则:内存中二进制补码按位取反,0变成1,1变成0。
#include <stdio.h>
int main()
{int a = 0;int b = ~a;printf("%d\n", b);return 0;
}
b = -1
3.5 例题
3.5.1 按位异或 ^ 拓展公式
异或 ^ 运算规则: 相同为0,不同为1。
a ^ a = 0 0 ^ a = a a ^ a ^ b =a ^ b ^ a (满足交换律)
3.5.2 不能创建临时变量(第三个变量),实现两个整数的交换。
方法1:创建第三个变量,交换,不符合题意。
#include <stdio.h>
int main()
{int a = 1;int b = 2;int c = 0;printf("交换前 a=%d b=%d\n", a, b);c = a;a = b;b = c;printf("交换后 a=%d b=%d\n", a, b);return 0;
}
方法2:a = a + b; b = a - b; a = a - b; 这种方法虽说可以完成运算,但是如果a 和 b 两个数很大,加起来就有可能超出整型的存储范围,存在数据溢出风险。
#include <stdio.h>
int main()
{int a = 1;int b = 2;printf("交换前 a=%d b=%d\n", a, b);a = a + b;b = a - b;a = a - b;printf("交换后 a=%d b=%d\n", a, b);return 0;
}
方法3:a = a ^ b; b = a ^ b; a = a ^ b;这种方法就不会存在数据溢出的情况。
#include <stdio.h>
int main()
{int a = 1;int b = 2;printf("交换前 a=%d b=%d\n", a, b);a = a ^ b;b = a ^ b;a = a ^ b;printf("交换后 a=%d b=%d\n", a, b);return 0;
}
但如果不是题目要求不能创建第三个变量,我们最多还是使用第一种方法,第三种方法不容易理解,且效率没有第一种方法高。
3.5.3 编写代码实现:求⼀个整数n存储在内存中的二进制中1的个数。
方法1:循环求出内存中存储的补码二进制的每一位,看是不是1,是1就加1,不是1不加,最后直到这个数等于0,停止循环。此方法对负数不适用。
为什么对负数不适用呢?
这种方法的本质上是将n /= 2当成n >>= 1,右移一位的本质是除以2,向下取整,相当于把n在内存中存储的二进制补码每一位都依次右移到最后一位,然后 % 2,取最后一位数看是不是1。
但是如果要把n /= 2当成n >>= 1,也要分情况来看,
当n是无符号整型时,右移是逻辑右移,左边直接补0,并且向下取整,等效于n/2 。
当n是有符号整型时,右移是算术右移,左边要补符号位,
n为非负数时,左边补0,等效于n/2,
n为负数时,左边补1,当n等于偶数时,等效于n/2,当n等于奇数时,n>>1相当于除以2并向下取整,-7>>1 = -4, -7 / 2 = -3 , 右移是向下取整,除法是取整接近0的数,两值不相等,就不等效于n/2。
所以n为-1时,-1 / 2 = 0;直接结束循环。这就可以改成方法2。
#include <stdio.h>
int main()
{int n = 0;int count = 0;scanf("%d", &n);while (n){if (n % 2 == 1){count++;}n /= 2;}printf("二进制中1的个数为:%d\n", count);return 0;
}
方法2:这种方法思路跟方法1有点相似, 如果n的最后一位是1,n&1 == 1,如果n的最后一位是0,n&1 == 0,整型一共32个二进制位,这里是把n的每一位都移到最后一位与1进行按位与(&)操作一共32位所以要循环32次,这里会把n右移一位的值赋值给n,改变了n的值。
#include <stdio.h>
int count(int n)
{int amount = 0;int i = 0;for (i = 0; i < 32; i++){if ((n & 1) == 1){amount++;}n >>= 1;}return amount;
}
int main()
{int n = 0;scanf("%d", &n);int a = count(n);printf("二进制中1的个数为:%d\n", a);return 0;
}
方法2副本: count函数里也可以写成下面这样,跟方法2思路有点差异。
这里是把n的每一位向右移动后的返回值与1进行按位与操作,这里不会改变n本身的值,只是把32位都一次性移动到最后一位与1进行&,最右边的一位移动0位就比较,以此类推,最左边一位要移到最右边一位,要移动31位,不改变n的值。
#include <stdio.h>
int count(int n)
{int amount = 0;int i = 0;for (i = 0; i < 32; i++){if (((n >> i) & 1) == 1){amount++;}}return amount;
}
int main()
{int n = 0;scanf("%d", &n);int a = count(n);printf("二进制中1的个数为:%d\n", a);return 0;
}
方法3:这里我们先拓展一个东西,如果一个整数n=7,
n在内存中的补码形式是00000000000000000000000000000111,
n-1 补码形式是00000000000000000000000000000110
n = n&n-1 补码形式是00000000000000000000000000000110
n-1 补码形式是00000000000000000000000000000101
n = n&n-1 补码形式是00000000000000000000000000000100
这里你会发现每次n&n-1后n在内存中的二进制最后面的1都会去掉,直到最后n=0,此时n在内存二进制中没有1。负数也同样适用。
那我们就可以写下下面的代码:
#include <stdio.h>
int main()
{int n = 0;int count = 0;scanf("%d",&n);while(n){n = n & (n-1);count++;}printf("二进制中1的个数为:%d\n", count);return 0;
}
方法3的运行次数就是数在内存中有几个1就运行几次,比方法1和方法2要效率高点。
3.5.4 整数内存二进制位置1或置0
//整数内存二进制位置1
#include <stdio.h>
int main()
{int n = 13;printf("%d\n", n);n |= 1 << (5 - 1);printf("%d\n", n);return 0;
}
假设有一个整数n,将n在内存中的二进制的第x位如果为1,先变0再变1,如果为0,先变1再变0。
这里我用n=13,第5位举例子。
13的原码=反码=补码=00000000000000000000000000001101,需要把从右往左第5位先变成1,再变成0。
置1:我们可以使用 | 操作符,将13的补码与00000000000000000000000000010000进行按位或操作,即:
00000000000000000000000000001101 |
00000000000000000000000000010000 =
00000000000000000000000000011101,这样就实现了第五位变成1,如何得到00000000000000000000000000010000,我们会发现将1的补码向左移动(5-1)位就可以得到。
即:1<<(5-1) == 00000000000000000000000000010000
代码如下:
//整数内存二进制位置1
#include <stdio.h>
int main()
{int n = 13;printf("%d\n", n);n |= 1 << (5 - 1);printf("%d\n", n);return 0;
}
置0:接着把00000000000000000000000000011101,的第5位置为0,该如何操作呢?
这里我们便用到 & 操作符,将00000000000000000000000000011101与11111111111111111111111111101111进行&操作。即:
00000000000000000000000000011101 &
111111111111111111111111111 01111 =
00000000000000000000000000001101,这样就实现了第五位变成0,如何得到111111111111111111111111111 01111,我们会发现00000000000000000000000000010000 按位取反会得到这个值,即进行 ~(1<<(5-1)) 操作。
~(1<<(5-1)) =111111111111111111111111111 01111
代码如下:
//整数内存二进制位置0
#include <stdio.h>
int main()
{int n = 13;printf("%d\n", n);n &= ~(1 << (5 - 1));printf("%d\n", n);return 0;
}
4. 逗号表达式
逗号表达式,就是用逗号隔开的多个表达式。
例如:(a,b,c,d)
逗号表达式是从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
int a = 1;
int b = 2;
int c = 4;
int d = ( a+b , a+c , b+c ) ;
d的值应该是最后一个表达式的结果,也就是b+c=6,所以d=6。
#include <stdio.h>
int main()
{int input = 0;while (printf("请输入一个整数:\n"), scanf("%d", &input) == 1){printf("%d\n", input);}return 0;
}
上图的代码也是可以的。
5. 下标引用[ ]和函数调用 ()
5.1 下标引用操作符[ ]
操作数是:数组名 + 索引值下标。
例如:
#include <stdio.h>
int main()
{int arr[10] = { 0 };arr[5] = 6;return 0;
}
arr[5] = 6; 中 arr和5是[ ] 的两个操作数。
5.2 函数调用操作符 ()
操作数是:函数名 + 参数 ,参数可有可无。
#include <stdio.h>
int add(a, b)
{return a + b;
}
int main()
{int a = 1;int b = 2;int c = add(a, b);printf("%d\n", c);return 0;
}
上面的add(a,b);中add和a,b是()的两个操作数。
6. 结构成员访问操作符 . ->
6.1 结构体
在C语言中,已经提供了很多内置类型int , long, char ,float ,double 等,但是光靠这些类型是无法满足我们编码所需要的,比如说:要定义一个学生的变量,需要姓名,身高,体重,学号,等。应该用什么类型呢,这时仅靠C语言中内置类型时无法满足的。
C语言提供了一种自定义类型,结构体,程序员可以自己创造想要的类型。
结构是一些值的集合,这些值称为成员变量,结构的每个成员可以是任意类型的,如标量、数组、指针,甚至是其他结构体。
6.1.1 结构体的声明
struct name
{member_list;}variable_list;
struct是声明结构体的关键字,name是结构体的名字,member_list是指结构体内的多个成员变量,variable_list是指多个结构体变量(可有可无)。
下面是定义的学生的结构体类型,包含姓名,年龄,性别,学号等成员变量,s1,s2,s3是直接创建的结构体变量(全局变量)。
struct student
{char name[20];//姓名int age;//年龄char sex[5];//性别char id[20];//学号}s1,s2,s3;
6.1.2 结构体变量的定义和初始化
下面代码定义结构体变量可以直接在结构体声明的同时定义,也可以直接定义。
初始化可以对应结构体里面的成员变量按顺序一一对应初始化,也可以不按顺序初始化,这时候
需要用到 . 操作符来访问结构体里面的成员变量来进行初始化,可以不按照顺序。
struct stu
{char name[20];int age;
}x1; //声明类型的同时定义结构体变量x1
struct stu x2; //定义结构体变量x2//按顺序初始化
struct stu x3 = {"张三",18};//不按顺序初始化
struct stu x4 = {.age = 18,.name = "张三"};
下面是结构体的嵌套情况下的初始化:
struct count
{int a;int b;
};struct arr
{int c;struct count;char b;
};struct s1 = {10,{20,30},'a'};
6.2 结构成员访问操作符
6.2.1 结构成员的直接访问
结构体成员的直接访问是通过点操作符(.)访问的。点操作符接受两个操作数。
通过结构体变量.成员变量名来访问成员变量。如下图:
#include <stdio.h>
struct Point
{int x;int y;
}p = {1,2};int main()
{printf("x: %d y: %d\n", p.x, p.y);return 0;
}
6.2.2 结构体成员的间接访问
结构体成员的间接访问是通过(->)操作符访问的。
通过结构体指针.成员变量名来访问成员变量。
当我们得到的不是⼀个结构体变量,而是⼀个指向结构体的指针。如下面代码:
#include <stdio.h>
struct Point
{int x;int y;
};int main()
{struct Point p = {3, 4};struct Point *ptr = &p;ptr->x = 10;ptr->y = 20;printf("x = %d y = %d\n", ptr->x, ptr->y);return 0;
}
这里ptr就是一个指向结构体的指针,通过ptr->x,ptr->y,来访问结构体中的成员变量。
7. 操作符的属性:优先级、结合性
7.1 优先级
优先级指的是,如果⼀个表达式包含多个运算符,哪个运算符应该优先执行。各种运算符的优先级是不一样的。
1 + 2 * 3;
例如:表达式 1 + 2 * 3 里面既有加法运算符( + ),⼜有乘法运算符( * )。由于乘法的优先级高于加法,所以会先计算 2 * 3 ,而不是先计算 1 + 2 。
7.2 结合性
如果两个运算符优先级相同,优先级没办法确定先计算哪个了,这时候就看结合性了,则根据运算符是左结合,还是右结合,决定执行顺序。大部分运算符是左结合(从左到右执行),少数运算符是右结合(从右到左执行),比如赋值运算符( = )就是从右到左执行。
1 * 2 / 3;
上面示例中, * 和 / 的优先级相同,它们都是左结合运算符,所以从左到右执行,先计算 1 * 2,再计算 2 / 3 。
运算符的优先级顺序很多,下面是部分运算符的优先级顺序(按照优先级从高到低排列),建议大家记住这些常用操作符的优先级就行,其他操作符在使用的时候查看下面表格就可以了。
• 圆括号( () )
• 自增运算符( ++ ),自减运算符(-- )
• 单目运算符( + 和 ) • 乘法( * ),除法( / ) • 加法( + ),减法( )
• 关系运算符( < 、 > 等)
• 赋值运算符( = )
由于圆括号的优先级最高,可以使用它改变其他运算符的优先级。
操作符优先级表格:
8. 表达式求值
8.1 整型提升
C语言中整型算术运算总是至少以缺省(默认)整型类型的精度来进行的。
在C语言中整型的默认类型是int类型,浮点型的默认类型是double类型,b = 100,要把100变成long类型,需要在100后面加上l,写成long b = 100l ; 浮点型同理要写成 float c = 3.14f ; 。
#include <stido.h>
int main()
{int a = 100;long b = 100l;float c = 3.14f;return 0;
}
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
下面代码中在进行 a+b的运算前,需要把a和b先转换成整型再参与运算。
#include <stdio.h>
int main()
{char a = 20;char b = 120;char c = a + b;printf("%d",c);return 0;
}
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。
通用CPU(general-purposeCPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为 int或unsigned int,然后才能送入CPU去执行运算。
上面代码中求出c的值等于多少? 答案是 -116 为什么呢?
char a = 20;
char b =120;
这里的20的二进制是:00000000000000000000000000010100
120的二进制是:00000000000000000000000001111000
但是a和b都是char类型,长度为1个字节(8个比特位),所以20和120分别赋值给a和b的二进制是
char a=20: 00010100
char b=120: 0111 1000
接下来计算char c = a + b;这时候要对a和b进行整型提升后再进行运算。
如何进行整型提升?
1. 有符号整数提升是按照变量的数据类型的符号位来提升的。
2. 无符号整数提升,高位补0。
而char类型是有符号整型,对a和b整型提升后的值是:
20: 000000000000000000000000 0001 0100
120: 000000000000000000000000 0111 1000
20+120 : 000000000000000000000000 1000 1100
此时把20+120赋值给c ,c是字符型。
char c =140 : 10001100
此时要打印c的值,而%d意思是打印一个有符号整型的十进制数。
所以要对c进行整型提升后再进行打印。
c整型提升后: 111111111111111111111111 1000 1100 --补码
100000000000000000000000 0111 0011
100000000000000000000000 0111 0100 --原码(-116)
所以打印出来c的结果位-116。
8.2 算数转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。
- long double
- double
- float
- unsigned long int
- long int
- unsigned int
- int
如果某个操作数的类型在上面这个列表中排名靠后,那么首先排名靠后的操作数类型要转换为排名靠前的操作数类型后再执行运算。
50 + 3.14f ;
这里的50是int类型,3.14是float类型,要先把50转换成float类型,再进行运算。(这个转换是编译器进行的)。
8.3 总结
即使有了操作符的优先级和结合性,我们写出的表达式依然有可能不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在潜在风险的,建议不要写出特别复杂的表达式。
相关文章:
C语言之操作符
目录 1. 操作符的分类 2. 移位操作符 2.1 左移操作符 << 2.2 右移操作符 >> 3. 位操作符 3.1 按位与 & 3.2 按位或 | 3.3 按位异或 ^ 3.4 按位取反 ~ 3.5 例题 3.5.1 按位异或 ^ 拓展公式 3.5.2 不能创建临时变量(第三个变量ÿ…...
【优选算法 | 前缀和】前缀和算法:高效解决区间求和问题的关键
算法相关知识点可以通过点击以下链接进行学习一起加油!双指针滑动窗口二分查找 在本篇文章中,我们将深入解析前缀和算法的原理。从基础概念到实际应用,带你了解如何通过前缀和高效解决数组求和、区间查询等问题。无论你是刚接触算法的新手&am…...
『深夜_MySQL』详解数据库 探索数据库是如何存储的
1. 数据库基础 1.1 什么是数据库 存储数据用文件就可以了,那为什么还要弄个数据库? 一般的文件缺失提供了数据的存储功能,但是文件并没有提供非常好的数据管理能力(用户角度,内容方面) 文件保存数据有以…...
Microsoft Entra ID 免费版管理云资源详解
Microsoft Entra ID(原 Azure AD)免费版为企业提供了基础的身份管理功能,适合小型团队或预算有限的组织。以下从功能解析到实战配置,全面展示如何利用免费版高效管理云资源。 1. 免费版核心功能与限制 1.1 功能概览 功能免费版支持情况基础用户与组管理✔️ 支持创建、删除…...
k8s -hpa
hpa定义弹性自动伸缩 1、横向伸缩,当定义的cpu、mem指标达到hpa值时,会触发pods伸展 2、安装metrics-server 收集pods的cpu。mem信息供hpa参照 安装helm curl -fsSl -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 用helm安装metr…...
Web应用开发指南
一、引言 随着互联网的迅猛发展,Web应用已深度融入日常生活的各个方面。为满足用户对性能、交互与可维护性的日益增长的需求,开发者需要一整套高效、系统化的解决方案。在此背景下,前端框架应运而生。不同于仅提供UI组件的工具库,…...
Vue3 + TypeScript 实现 PC 端鼠标横向拖动滚动
功能说明 拖动功能: 鼠标按下时记录初始位置和滚动位置拖动过程中计算移动距离并更新滚动位置松开鼠标后根据速度实现惯性滚动 滚动控制: 支持鼠标滚轮横向滚动(通过 wheel 事件)自动边界检测防止滚动超出内容…...
MyBatis的SQL映射文件中,`#`和`$`符号的区别
在MyBatis的SQL映射文件中,#和$符号用于处理SQL语句中的参数替换,但它们的工作方式和使用场景有所不同。 #{} 符号 预编译参数:#{} 被用来作为预编译SQL语句的占位符。这意味着MyBatis会将你传入的参数设置为PreparedStatement的参数,从而防止SQL注入攻击,并允许MyBatis对…...
Python----卷积神经网络(池化为什么能增强特征)
一、什么是池化 池化(Pooling)是卷积神经网络(CNN)中的一种关键操作,通常位于卷积层之后,用于对特征图(Feature Map)进行下采样(Downsampling)。其核心目的是…...
React Native 从零开始完整教程(环境配置 → 国内镜像加速 → 运行项目)
React Native 从零开始完整教程(环境配置 → 国内镜像加速 → 运行项目) 本教程将从 环境配置 开始,到 国内镜像加速,最后成功运行 React Native 项目(Android/iOS),适合新手和遇到网络问题的开…...
SNR8016语音模块详解(STM32)
目录 一、介绍 二、传感器原理 1.原理图 2.引脚描述 三、程序设计 main文件 usart.h文件 usart.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 SNR8016语音模块是智纳捷科技生产的一种离线语音识别模块,设计适合用于DIY领域,开放用户设…...
驱动开发系列54 - Linux Graphics QXL显卡驱动代码分析(一)设备初始化
一:概述 QXL 是QEMU支持的一种虚拟显卡,用于虚拟化环境中的图形加速,旨在提高虚拟机的图形显示和远程桌面的用户体验;QEMU 也称 Quick Emulator,快速仿真器,是一个开源通用的仿真和虚拟化工具,可…...
通过IP计算分析归属地
在产品中可能存在不同客户端,请求同一个服务端接口的场景。 例如小程序和App或者浏览器中,如果需要对请求的归属地进行分析,前提是需要先获取请求所在的国家或城市,这种定位通常需要主动授权,而用户一般是不愿意提供的…...
【网络原理】从零开始深入理解HTTP的报文格式(二)
本篇博客给大家带来的是网络HTTP协议的知识点, 续上篇文章,接着介绍HTTP的报文格式. 🐎文章专栏: JavaEE初阶 🚀若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅…...
【前缀和】二维前缀和(模板题)
DP35 【模板】二维前缀和 DP35 【模板】二维前缀和 给你一个 n 行 m 列的矩阵 A ,下标从 1 开始,接下来有 q 次查询,每次查询输入 4 个参数 x1 , y1 , x2 , y2。 请输出以 (x1, y1) 为左上角,(x2,y2) 为右下角的子矩阵的和。 输入描述: 第一行包含三个整数 …...
【开源工具】Python打造智能IP监控系统:邮件告警+可视化界面+配置持久化
🌐【开源工具】Python打造智能IP监控系统:邮件告警可视化界面配置持久化 🌈 个人主页:创客白泽 - CSDN博客 🔥 系列专栏:🐍《Python开源项目实战》 💡 热爱不止于代码,热…...
kotlin 过滤 filter 函数的作用和使用场景
1. filter 函数的作用 filter 是 Kotlin 集合操作中的一个高阶函数,用于根据指定条件从集合中筛选出符合条件的元素。 作用:遍历集合中的每个元素,并通过给定的 lambda 表达式判断是否保留该元素。返回值:一个新的集合ÿ…...
Java泛型(补档)
核心概念 Java 泛型是 Java SE 1.5 引入的一项重要特性,它的核心思想是 参数化类型(Parameterized Types),即通过将数据类型作为参数传递给类、接口或方法,使代码能够灵活地处理多种类型,同时保证类型安全性…...
C语言发展史:从Unix起源到现代标准演进
C语言发展史:从Unix起源到现代标准演进 C语言的诞生与早期发展 C语言的起源可以追溯到上世纪70年代初期,但其真正的萌芽始于1969年的夏天。在计算机发展史上,这是一个具有划时代意义的时刻。 当时,Ken Thompson和Dennis Ritchi…...
nginx 代理时怎么更改 Remote Address 请求头
今天工作中遇到用 localhost 访问网站能访问后台 api,但是用本机IP地址后就拒绝访问,我怀疑是后台获取 Remote Address 然后设置白名单了只能 localhost 访问。 想用 nginx 更改 Remote Address server {listen 8058;server_name localhost;loca…...
解决STM32待机模式无法下载程序问题的深度探讨
在现代嵌入式系统开发中,STM32系列微控制器因其高性能、低功耗和丰富的外设资源而广受欢迎。然而,开发者在使用STM32时可能会遇到一个问题:当微控制器进入待机模式后,无法通过调试接口(如SWD或JTAG)下载程序…...
进程、线程、进程间通信Unix Domain Sockets (UDS)
进程、线程、UDS 进程和线程进程间通信Unix Domain Sockets (UDS)UDS的核心适用场景和用途配置UDS的几种主要方式socketpair() 基本配置流程socketpair() 进阶——传递文件描述符 补充socketpair() 函数struct msghdr 结构体struct iovecstruct cmsghdrstruct iovec 、struct m…...
大数据平台与数据仓库的核心差异是什么?
随着数据量呈指数级增长,企业面临着如何有效管理、存储和分析这些数据的挑战。 大数据平台和 数据仓库作为两种主流的数据管理工具,常常让企业在选型时感到困惑,它们之间的界限似乎越来越模糊,功能也有所重叠。本文旨在厘清这两种…...
Hadoop虚拟机中配置hosts
( 一)修改虚拟机的主机名 默认情况下,本机的名称叫:localhost。 我们进入linux系统之后,显示出来的就是[rootlocalhost ~]# 。为了方便后面我们更加便捷地访问这台主机,而不是通过ip地址,我们要…...
a-upload组件实现文件的上传——.pdf,.ppt,.pptx,.doc,.docx,.xls,.xlsx,.txt
实现下面的上传/下载/删除功能:要求支持:【.pdf,.ppt,.pptx,.doc,.docx,.xls,.xlsx,.txt】 分析上面的效果图,分为【上传】按钮和【文件列表】功能: 解决步骤1:上传按钮 直接上代码: <a-uploadmultip…...
QCefView应用和网页的交互
一、demo的主要项目文件 结合QCefView自带的demo代码 main.cpp #include #include <QCefContext.h> #include “MainWindow.h” int main(int argc, char* argv[]) { QApplication a(argc, argv); // build QCefConfig QCefConfig config; config.setUserAgent(“QCef…...
C++,设计模式,【建造者模式】
文章目录 通俗易懂的建造者模式:手把手教你造电脑一、现实中的建造者困境二、建造者模式核心思想三、代码实战:组装电脑1. 产品类 - 电脑2. 抽象建造者 - 装机师傅3. 具体建造者 - 电竞主机版4. 具体建造者 - 办公主机版5. 指挥官 - 装机总控6. 客户端使…...
Axure疑难杂症:中继器制作下拉菜单(多级中继器高级交互)
亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! Axure产品经理精品视频课已登录CSDN可点击学习https://edu.csdn.net/course/detail/40420 本文视频课程记录于上述地址第五章中继器专题第11节 课程主题:中继器制作下拉菜单 主要内容:创建条件选区、多级中继器…...
科研 | 光子技术为人工智能注入新动力
译《Nature》25.4.9 发表文章《A photonic processing boost for AI》 ▶ 基于人工智能(artificial intelligence, AI)的系统正被越来越广泛地应用于从基因数据解码到自动驾驶的各类任务。但随着AI模型的规模和应用的扩大,性能天花板与能耗壁…...
SQL语句练习 自学SQL网 多表查询
目录 Day 6 用JOINs进行多表联合查询 Day 7 外连接 OUTER JOINs Day 8 外连接 特殊关键字 NULLs Day 6 用JOINs进行多表联合查询 SELECT * FROM Boxoffice INNER JOIN movies ON movies.idboxoffice.Movie_id;SELECT * FROM Boxoffice INNER JOIN moviesON movies.idboxoffi…...
北京亦庄机器人马拉松:人机共跑背后的技术突破与产业启示
2025年4月19日,北京亦庄举办了一场具有里程碑意义的科技赛事——全球首个人形机器人半程马拉松。这场人类与20支机器人战队共同参与的21.0975公里竞速,不仅创造了人形机器人连续运动的最长纪录,更成为中国智能制造领域的综合性技术验证平台。…...
大连理工大学选修课——机器学习笔记(6):决策树
决策树 决策树概述 决策树——非参数机器学习方法 参数方法: 参数估计是定义在整个空间的模型 所有训练数据参与估算 所有的检验输入都用相同的模型和参数 非参数方法: 非参数估计采用局部模型 输入空间被分裂为一系列可以用距离度量的局部空间…...
现代前端工具链深度解析:从包管理到构建工具的完整指南
前言 在当今快速发展的前端生态中,高效的工具链已经成为开发者的必备利器。一个优秀的前端工具链可以显著提升开发效率、优化项目性能并改善团队协作体验。本文将深入探讨现代前端开发中最核心的两大工具类别:包管理工具(npm/yarn)和构建工具(Webpack/V…...
[C语言]猜数字游戏
文章目录 一、游戏思路揭秘二、随机数生成大法1、初探随机数:rand函数的魔力2、随机数种子:时间的魔法3、抓住时间的精髓:time函数 三、完善程序四、游戏成果1、游戏效果2、源代码 一、游戏思路揭秘 猜数字游戏,这个听起来就让人…...
【Linux】g++安装教程
Linux上安装g教程 实现c语言在Linux上编译运行 1. 更新软件包列表 打开终端,先更新软件包列表以确保获取最新版本信息: sudo apt update2. 安装 build-essential 工具包 build-essential 包含 g、gcc、make 和其他编译所需的工具: sudo…...
MQTT - Android MQTT 编码实战(MQTT 客户端创建、MQTT 客户端事件、MQTT 客户端连接配置、MQTT 客户端主题)
Android MQTT 编码实战 1、Settting 在项目级 build.gradle 目录下导入 MQTT 客户端依赖 implementation org.eclipse.paho:org.eclipse.paho.mqttv5.client:1.2.5 implementation org.eclipse.paho:org.eclipse.paho.android.service:1.1.1AndroidManifest.xml,…...
Redis分布式锁使用以及对接支付宝,paypal,strip跨境支付
本章重点在于如何使用redis的分布式锁来锁定库存。减少超卖,同时也对接了支付宝,paypal,strip跨境支付 第一步先建立一个商品表 CREATE TABLE sys_product (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键,code varchar(60) DEFAUL…...
沙箱逃逸(Python沙盒逃逸深度解析)
沙箱逃逸(Python沙盒逃逸深度解析) 一、沙盒逃逸的核心目标 执行系统命令 通过调用os.system、subprocess.Popen等函数执行Shell命令,例如读取文件或反弹Shell。 文件操作 读取敏感文件(如/etc/passwd)、写入后门文件…...
k8s-Pod生命周期
初始化容器 初始化容器是在pod的主容器启动之前要运行的容器,主要是做一些主容器的前置工作,它具有两大特征: 1. 初始化容器必须运行完成直至结束,若某初始化容器运行失败,那么kubernetes需要重启它直到成功完成 2. 初…...
基于Springboot + vue实现的中医院问诊系统
项目描述 本系统包含管理员、医生、用户三个角色。 管理员角色: 用户管理:管理系统中所有用户的信息,包括添加、删除和修改用户。 配置管理:管理系统配置参数,如上传图片的路径等。 权限管理:分配和管理…...
computed计算值为什么还可以依赖另外一个computed计算值?
在 Vue(或类似的响应式框架)中,computed 计算属性之所以可以依赖另一个 computed 属性,是因为: ✅ 本质上 computed 是响应式依赖的“派生值” 每个 computed 本质上就是一个 基于其他响应式数据计算出来的值。 当你在…...
近期实践总结
一、计算机二级考试到底教会了我们什么? 1、概况 根据本人复习、考试的经验,不难发现里面的试题或多或少有些死板(甚至可以说落后于时代),当今时代已经不是二十年前什么都需要手搓的时代了,引擎、集成类软…...
Arduion 第一天,变量的详细解析
Arduino变量详解与嵌入式开发扩展 一、变量基础篇 1.1 变量声明与初始化 <ARDUINO>int ledPin 13; // 声明并初始化float sensorValue; // 先声明后赋值unsigned long startTime; // 无符号长整型void setup() {sensorValue analogRead(A0) *…...
【每日八股】复习 MySQL Day3:锁
文章目录 昨日内容复习MySQL 使用 B 树作为索引的优势是什么?索引有哪几种?什么是最左匹配原则?索引区分度?联合索引如何排序?使用索引有哪些缺陷?什么时候需要建立索引,什么时候不需要…...
2025年KBS新算法 SCI1区TOP:长颖燕麦优化算法AOO,深度解析+性能实测
目录 1.摘要2.算法原理3.结果展示4.参考文献5.文章&代码获取 1.摘要 本文提出了一种新颖的元启发式算法——长颖燕麦优化算法(AOO),该算法灵感来自动画燕麦在环境中的自然行为。AOO模拟了长颖燕麦的三种独特行为:(i) 通过自然…...
1.4 点云数据获取方式——结构光相机
图1-4-1结构光相机 结构光相机作为获取三维点云数据的关键设备,其工作原理基于主动式测量技术。通过投射已知图案,如条纹、点阵、格雷码等,至物体表面,这些图案会因物体表面的高度变化而发生变形。与此同时,利用相机从特定...
2025.4.29总结
工作:最近手头活变得多起来了,毕竟要测两个版本,有时候觉得很奇怪,活少的时候,又想让别人多分点活,活多的时候,又会有些许不自然。这种反差往往伴随着项目的节奏,伴随着两个极端。所…...
初探RAG
源码 核心工作流程 读取文件的内容将内容保存在向量数据库检索向量数据库用户的问题用户问题 上下文【向量数据】 > LLM 读取文件内容【pdf为例】 from pdfminer.high_level import extract_pages from pdfminer.layout import LTTextContainerclass PDFFileLoader():d…...
AIGC(生成式AI)技术全景图:从文本到图像的革命
AIGC(生成式AI)技术全景图:从文本到图像的革命 前言 生成式人工智能(AIGC)正以惊人的速度重塑数字内容的生产方式。从GPT系列模型的文本生成,到Stable Diffusion的图像创作,再到Sora的视频合成…...
通信协议:数字世界的隐形语言——从基础认知到工程实践-优雅草卓伊凡
通信协议:数字世界的隐形语言——从基础认知到工程实践-优雅草卓伊凡 一、理解通信协议:数字世界的”隐形语法” 1.1 通信协议的不可见性与现实存在 通信协议如同空气中的无线电波,虽然看不见摸不着,却实实在在支撑着现代数字世…...