操作符详细解析

news2024/11/15 14:05:07

操作符详解

文章目录

  • 操作符详解
    • 1.操作符分类
    • 2.算数操作符
    • 3.移位操作符
      • 3.1整型二进制的表示
        • 3.1.1整数二进制的种类
        • 3.1.2二进制原码反码补码的表示
      • 3.2移位运算符使用规则
        • 3.2.1正数的左移运算符
      • 3.2.2负数的左移运算符
      • 3.2.3右移操作符
        • 3.2.3.1右移运算符的两种形式:
        • 3.2.3.2怎么判断是算数右移还是逻辑右移
    • 4.位操作符
      • 4.1异或(^)的特点
      • 4.2计算一个整数换算为二进制时1的个数
    • 5.赋值操作符
      • 5.1复合赋值符
    • 6.单目操作符
      • 6.1单目操作符简单介绍
      • 6.2单目操作符与双目操作符
      • 6.3"!"操作符
      • 6.4"&"操作符
      • 6.5"sizeof"操作符
      • 6.6"~"操作符
      • 6.7"++"和"--"的前置与后置
      • 6.8"*"操作符
      • 6.9强制类型转换
      • 6.10"sizof"操作符
    • 7.关系操作符
      • 7.1"=="操作符
    • 8.逻辑操作符
    • 9.条件操作符
    • 10.逗号表达式
    • 11下标引用、函数调用和结构成员
      • 11.1下标引用操作符"[]"
        • 11.1.1下标引用操作符"[]"的其他用法
      • 11.2函数调用操作符"()"
      • 11.3结构体
    • 12.表达式求值
    • 12.1运算符的优先级
      • 12.2隐式类型转换
      • 12.2.1整型提升的意义
      • 12.3算数转换

1.操作符分类

算术操作符

移位操作符

位操作符

赋值操作符

单目操作符

关系操作符

逻辑操作符

条件操作符

逗号表达式

下标引用,函数调用和结构成员

2.算数操作符

+ -	*	/

其他的运算符就正常的该++,该–。

除(/):简单来说就是去余取整(去掉余数部分取整数部分)

整型的除法	1/2 ——> 0	就是去余取整(去掉余数部分取整数部分)
浮点型的除法	1.0/2 ——> 0.5	除数或被除数有一个是0,那么结果就可以是浮点型

取模(%):简单来说就是去整取余,取模操作符的两端必须是整型

7%2 ——> 1//7/2...1

3.移位操作符

<< 左移位操作符

>> 右移位操作符

注:移位操作符的操作数只能是整数。

使用的对象:移位操作符,移动的是二进制

警告:对于移位运算符,不要移动负数位,这个是标准未定义的。

例如:

int num = 10;
num >> -1;//error

3.1整型二进制的表示

3.1.1整数二进制的种类

整数的二进制表示有3种

原码 反码 补码

正的整数的原码,反码,补码相同

负的整数的原码,反码,补码是要计算的

3.1.2二进制原码反码补码的表示

以7为例(7是整数,单位是字节)

7的二进制是111

正的整数

00000000000000000000000000000111最高位是0表示正数,表示7 -原码 -反码 -补码

负的整数

10000000000000000000000000000111最高位是1表示负数,表示-7 -原码

1111111111111111111111111111000 -7 -反码(原码的符号位(最高位)不变,其他位按位取反就是反码)

1111111111111111111111111111001 -7 -补码 (反码+1就是补码)

电脑在内存中存储的是补码

3.2移位运算符使用规则

3.2.1正数的左移运算符

“左边丢弃,右边补0”

int a = 7;
int b = a << 1;// 14
printf("%d\n",a);
prnttf("%d",b);
//输出: 7
//     14

由输出结果可得,a数值没有改变,被赋值的b数值变了。与b = a + 1;的理解相似。

如图所示:

把a向左移动一位,就是把从这个状态

在这里插入图片描述

移动到这个状态

在这里插入图片描述

移位前是111也就是7,移位后1110也就是14

3.2.2负数的左移运算符

实行移动操作是对这个整数的补码进行操作的。

-7的补码为1111111111111111111111111111001

int a = -7;
int b = a << 1;// -14
printf("%d\n",a);
prnttf("%d",b);
//输出: -7
//     -14

如图所示:

-7的补码

在这里插入图片描述

左移动1位后(<<1)

在这里插入图片描述

移动后b里面的补码是

在这里插入图片描述

如果需要看出补码的大小,就需要计算一下:

补码 = 原码——>反码——>反码+1,所以原码 = 补码-1——>取反

3.2.3右移操作符

3.2.3.1右移运算符的两种形式:
  1. 算术移位

“右边丢弃,左边补原符号位”

  1. 逻辑移位

“右边丢弃,左边补0”

以7为例子00000000000000000000000000000111

如下图所示:

在这里插入图片描述

如果去掉右边的1没有问题,那么最高位表示正负就成了问题。这就涉及了两种移位。

3.2.3.2怎么判断是算数右移还是逻辑右移

使用负数就可以判断。

一般的编译器都是算数移位。如vs,

4.位操作符

位操作符有

& //按(二进制)位与

| //按(二进制)位或

^ //按(二进制)位异或

注:它们的操作数必须是整数

电脑内存的是整数的补码,所以使用补码计算

# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main() {
	int a = 3;
	int b = -5;
	//按位与
	//11111111111111111111111111111011 -5的补码
	//00000000000000000000000000000011	3的补码
	//00000000000000000000000000000011	3 & -5 = 3;两个都是1才为1,有一个是0,就是0。为正数,所以原码就是这个。
	int c = a & b;
	//按位或
	//11111111111111111111111111111011 -5的补码
	//00000000000000000000000000000011	3的补码
	//11111111111111111111111111111011  3|-55 = -5;两者其中一个是1就为1,两个都是0,为0。为负数,所以另求原码
	int d = a | b;
	//按位异或
	//11111111111111111111111111111011 -5的补码
	//00000000000000000000000000000011	3的补码
	//11111111111111111111111111111000	3 ^ -5 = -8;两者相同为0,两者相异为1。为1,为负数,所以另求原码。
	int e = a ^ b;
	printf("c=%d\n", c);
	printf("c=%d\n", d);
	printf("c=%d\n", e);
}

4.1异或(^)的特点

3 ^ 3 = 0;
3 ^ 0 = 3;
3 ^ 3 ^ 5 =0;
3 ^ 5 ^ 3 =0;//说明异或支持交换律

我们可以得出

a ^ a = 0;
a ^ 0 = a;
a ^ a ^ b = b;
a ^ b ^ b = a;

然后感受一下下面的代码:

不使用第三个变量交换两个整数变量的值。

# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main() {
	int a = 3;
	int b = 5;
	printf("交换之前的a=%d,b=%d\n", a, b);
	a = a ^ b;//3^5
	b = a ^ b;//3^5^5=3
	a = a ^ b;//3^3^5=5
	printf("交换之后的a=%d,b=%d", a, b);
}

4.2计算一个整数换算为二进制时1的个数

小提示:可以使用a&1,如果第一位为1,那么&1后的结果会是1,如果第一位不是1,那么&1后的结果就会使0……以此类推。

5.赋值操作符

“=”:可以给变量重新的赋值

int weight = 200;//体重
weight = 89;

赋值操作符可以连续使用,比如:

int a = 10;
int b = 0;
int c = 20;
a = b = c+1;//连续使用,连续赋值,但是可读性较差,一般不这么些

//一般写成这样
a = c+1;
a = b;

初始化与赋值的区别:

int a = 3;//在定义变量的时候直接给数值,就是初始化
a = 5;//重新指定数值为赋值

5.1复合赋值符

+=

-=

*=

/=

%=

>>=

<<=

&=

|=

^=

这些运算符都可以写成复合的效果。比如:

int a = 3;
a = a + 5;
//等同于
a += 5;
a = a<< 1;
//等同于
a <<= a;

6.单目操作符

6.1单目操作符简单介绍

! 逻辑反操作

- 负值

+ 正值

& 取地址

sizeof 操作数的类型的大小(以字节为单位)
				对一个数的二进制按位取反

– 前置、后置–

++ 前置、后置++

* 间接访问操作符(解引用操作符)

(类型) 强制类型转换

6.2单目操作符与双目操作符

单目操作符:只有一个操作数

以"+"为例,+既可以表示正值 (虽然意义不大),又可以表示相加

a+b;//双目操作符	+操作符有两个操作数

6.3"!"操作符

"!"操作符就是取反的操作,真的取反就变成假的。

int main() {
	int flag = 1;
	if (flag)
	{
		printf("通过第一个判断语句");
	}
    //取反
	if (!flag)
	{
		printf("这个语句是输出不了的");
	}
}

什么是真假?在c语言中0表示假,1表示真。

6.4"&"操作符

"&"操作符就是取地址。

int a = 10;
printf("%p",&a);//取a的地址,并输出

6.5"sizeof"操作符

"sizeof"操作符就是计算类型或者变量所占空间的大小。(单位都是字节)

int a = 10;
int n = szieof(int);//计算类型所占内存空间的大小
printf("%d",n);

如果传入的参数是数组名,那么计算的将会是整个数组所占空间的大小。

6.6"~"操作符

"~"操作符:作用就是按(二进制)位取反。

int main() {
	//操作符~
	int a = 0;
	//00000000000000000000000000000000 - a 原码
	//11111111111111111111111111111111 - ~a 取反操作(但数据形式还是补码)
	//11111111111111111111111111111110 - 反码(补码-1等于反码)
	//10000000000000000000000000000001 - 原码(反码取反就是原码,取反时最高位不变)
	printf("%d", ~a);//输出:-1(10000000000000000000000000000001)
}

6.7"++“和”–"的前置与后置

“++“和”–”,等同于n = n + 1;就是自增1和自减1

++ 和 --前置后置,++前置先自增,后置先使用;–前置先自减,后置先使用;

int main() {
	int a = 10;
	int b1 = a++;//输出:10,后置++,先赋值,后自增
	int c = 10;
	int d1 = ++c;//输出:11,前置++,先自增,后赋值

	printf("%d\n", b1);
	printf("%d\n", a);//输出:11
	printf("%d\n", d1);
	printf("%d\n", c);//输出:11
}

可能会误判的情况:

int a = 10;
printf("%d",a--);//输出:10
printf("%d",a);//输出:9

这种情况也是使用。

6.8"*"操作符

"*"操作符,间接访问操作符(又称解引用操作符),与指针配合使用

int a = 10;
int *p = &a;
*p = 20;
printf("%d",a);//输出:20

*就是通过指针访问变量本体,就是说*p 等同于a。

6.9强制类型转换

(想要修改的类型):就可以将其修改为想要的类型。

int e = 3.14;//字面的浮点型系统会默认是double类型的
int f = (int)3.14;//括号 类型 括号(类型),强制类型转换,这里将double类型转换为整型
printf("%d\n", e);
printf("%d", f);

6.10"sizof"操作符

"sizof"操作符:计算操作数的字符长度(以字节为单位).

sizeof作为单目操作符与函数的区别:

调用sizeof可以不加括号,在语法允许的情况下。

#include <stdio.h>

int main() {
	int a = 0;
	printf("%d\n", sizeof(a));//输出:4
	printf("%d\n", sizeof(int));//输出:4,int的大小必须要加括号,否则语法不允许
	printf("%d\n", sizeof a);//输出:4,因为是单目操作符,所以括号可写可不写


	int arr[10] = { 0 };
    //计算整个数组的大小,单位是字节
	printf("%d\n", sizeof(arr));//输出:40
    //计算一个元素的大小
	printf("%d\n", sizeof(arr[0]));//输出:4,一个整型元素的大小
    //常用操作计算元素的个数
	printf("%d\n", sizeof(arr) / sizeof(arr[0]));//输出:10


	return 0;
}

试着判断下面4处的输出结果:

# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

void test1(int arr[]) {
	printf("%d\n", sizeof(arr));//第三处
}
void test2(char ch[]) {
	printf("%d\n", sizeof(ch));//第四处
}

int main() {
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("%d\n", sizeof(arr));//第一处
	printf("%d\n", sizeof(ch));//第二处
	test1(arr);
	test2(ch);
}

输出结果:

第一处:40,整型的大小为4,整型数组元素个数为10,所以是40.

第二处:10,字符的大小为1,字符数组元素个数为10,所以是10

第三处:4或8,看起来传过去的时数组其实是该数组第一个元素的地址,也就是指针,指针变量的大小的一样所以是4或8(32位4,64位8)。

第四处:4或8,看起来传过去的时数组其实是该数组第一个元素的地址,也就是指针,指针变量的大小的一样所以是4或8(32位4,64位8)。

7.关系操作符

>

>=

<

<=

!= 用于测试“不相等”

== 用于测试“相等”

7.1"=="操作符

"=="操作符用于判断是否相等

"=="用于判断浮点型的数据时可能会不准确

if(3.0==5.0){
    return 0;
}

"=="用于比较字符串时,其实比较的是两个字符串的首字符地址。

两个字符串的比较应该使用strcmp函数来比较。

8.逻辑操作符

&& 逻辑与

|| 逻辑或

观察下面代码得出结论:

int main() {
	int i = 0, a = 0, b = 2, c = 3;
	i = a++ && ++b && c++;

	printf("a=%d,b=%d,c=%d", a, b, c);
}
//输出:a=1,b=2,b=3
//因为a=0,所以逻辑与不成立,判定为假,后续就不计算了
int main() {
	int i = 0, a = 1, b = 2, c = 3;
	i = a++ && ++b && c++;
    
	printf("a=%d,b=%d,c=%d", a, b, c);
}
//输出:a=2,b=3,c=4;
//因为a!=0,为真,b!=0为真,c!=为真,所以3个都计算过去
int main() {
	int i = 0, a = 1, b = 2, c = 3;

	i = a++ || ++b || c++;
	printf("a=%d,b=%d,c=%d", a, b, c);
}
//输出:a=2,b=2,c=3;
//因为a!=0,为真,所以逻辑或后面不计算了

&& 左边为假,右边就不计算了

||左边为真,右边就不计算了

9.条件操作符

又称三目操作符

exp1 ? exp2 : exp3

表达式exp1成立,则执行表达式exp2,表达式exp1不成立,执行表达式exp3.

例子:

int b = 0;
int a = 3;
//判断a是否大于5,大于5,b=3,小于5,b=-3
b = (a > 5 ? 3:-3);
//显然a<5,所以b=-3.

10.逗号表达式

公式从左到右依次计算,计算结果为最右边的公式的结果

exp1,exp2,exp3……expn

例子:

	//代码1
	int a = 6;
	int b = 4;
	int c = (a + b, a - b, a * b);//最后的结果为:a*b(最右边的公式)
	printf("%d", c);
//输出:

	//代码2
	if(a = n + 1, c = a/2 , d < 0);//虽然逗号表达式是看最后一个结果的,但是前面的过程是不可忽略的

	//代码3
	a = get_val();
	count_val(a);
	while(a > 0){
        a = get_val;
        count_val(a);
    }

	//如果使用逗号表达式,改写:
	//		1		2			3
	while(get_val,count_val(a),a<0){//虽然只看最后一步,但前两步必不可少
       //业务处理
    }

11下标引用、函数调用和结构成员

[]  ()  .  ->

11.1下标引用操作符"[]"

下标引用操作符是**“[]”,但定义数组的"[]"**,不是下标引用操作符

	//这里的[]是定义数组的符号,不是下标引用操作符	
	int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
	int a = 3;
	//[]就是下标引用操作符,arr和3就是操作数
	printf("%d", arr[a]);
11.1.1下标引用操作符"[]"的其他用法
int main(){
    int arr[10] = 0;
    //想象一下arr[7],就是arr数组首个元素的指针+7,就是指向了第8个元素
    //指针+7与7+指针大小是相等的
    //arr[7] --> *(arr+7) -->*(7+arr) -->7[arr]
    
    //arr是数组元素的首个地址
    //arr+7就是跳过7个元素,指向了第8个元素
    //*(arr+7)就是第8个元素
    arr[7] = 8;
    //这种写法是没有错误的
    7[arr] = 9;
    //所以可以正常使用
    
    
}

11.2函数调用操作符"()"

int add(int a, int b){
	int z = a + b;
	return z;
}
int main() {
    int a = 2;
    int b = 3;
    //()就是函数调用的操作符,add,a,b就是()的操作数,括号不能省略
	printf("%d", result);
	int result = add(a, b);
	return 0;
}

11.3结构体

结构体是把一些单一类型的组合在一起。

定义结构体的关键字是:struct

定义结构体,创建结构体实例,并输出

# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

//使用struct关键字创建结构体my_info
struct my_info {
	int age;
	char name[20];
	char sex[10];
	char tel[12];
};

//通过指针获取结构体的信息,并设置
void set_struct(struct my_info* ss) {
    //使用*指针来获取元素并赋值
	/*(*ss).age = 21;
	strcpy((*ss).name , "czl");
	strcpy((*ss).sex ,"man");
	strcpy((*ss).tel ,"123456");*/
    //使用箭头运算符,通过指针来访问成员并赋值
	ss->age = 21;
	strcpy(ss->name, "czl");
	strcpy(ss->sex, "man");
	strcpy(ss->tel, "123456");
	
}

//通过指针获取结构体信息,并输出
void print_info(struct my_info* sss)
{
    //可通过*指针获取元素
	/*printf("%d\n", (*sss).age);
	printf("%s\n", (*sss).name);
	printf("%s\n", (*sss).sex);
	printf("%s\n", (*sss).tel);*/
    //使用箭头运算符,通过指针来访问其成员
	printf("%d\n", sss->age	);
	printf("%s\n", sss->name);
	printf("%s\n", sss->sex);
	printf("%s\n", sss->tel);
};

int main() {
	//初始化自定义结构体
	struct my_info s= { 0 };
	set_struct(&s);
	print_info(&s);
}

上述代码种可能存在的疑问!

  1. 为什么给字符串赋值要调用strcpy函数?

​ 在c语言中,字符串是以字符数组的形式存在,没有直接的赋值操作。因此,需要将字符串赋值到另一个字符串就需要strcpy函数来复制内容。

如果使用=来赋值,那么只会复制该字符串(字符数组)的首元素地址,不会复制全部的内容。

  1. 传参为什么要传指针?

​ 普通的传参只是函数内多出一个参数的副本,并非参数本参。

​ 如果需要在函数内部修改参数的值,则需要传递变量的指针(即变量的地址),然后通过指针直接访问参数本参,进行的修改操作将直接作用于传递的参数本省,而非副本。

12.表达式求值

表达式求值的顺序一部分是由操作符的优先级和结合性决定。

同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。

12.1运算符的优先级

在这里插入图片描述

12.2隐式类型转换

c的整型整数运算总是以缺省整型类型的精度来计算的。

为了获取这个精度,表达式的字符和短整型操作数在使用之前通常会被转化为普通类型,这种转换被称为整型提升

12.2.1整型提升的意义

整型提升的意义

表达式的整型运算要在CPU的相应运算器内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。

因此,即使是两个char类型的相加,在CPU执行时实际上也要先转换位CPU内整型操作数的标准长度。

通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加的指令)。所以,表达式中各种长度小于int长度的整型值,都必须先转换为int或unsigned int),然后才能送入CPU去执行运算。

比如:

int a,b,c;
...
a = b + d;

b和c的值被提升为普通整型,然后再执行加法运算。

加法运算完成之后,结果将被截断,然后再存储于a中。

如何进行型体提升呢?

整型提升是按照变量的数据类型的符号位来提升的。

	//负数的整型提升
	char a= -1;
	//10000000000000000000000000000001 -1
	//11111111111111111111111111111110 -反码
	//11111111111111111111111111111111 -补码(32比特)
	//变量a的二进制(补码)只有8个比特位:
	//11111111 -char类型(后8位)
	//因为char,为有符号的char
	//所以整型提升的时候高位补充符号位,即1
	//提升之后的结果是:
	//11111111111111111111111111111111


	//正数的整型提升
	char b = 1;
	//00000000000000000000000000000001 -1
	//变量b的二进制(补码)只有8个比特位:
	//00000001 -char类型
	//因为char,为有符号的char
	//所以整型提升的时候,高位补充符号位,即0
	//提升之后的结果是:
	//00000000000000000000000000000001

	//无符号整型提升,高位补0

整型提升运用的例子:

计算字符类型的整数的相加。

int main() {
	char a = 5;
	//相加需要整型提升
	//00000000000000000000000000000101	-a原码
	//00000101	-a内存储的
	//00000000000000000000000000000101	-整型提升后
	char b = 126;
	//00000000000000000000000001111110	-b原码
	//01111110	-b内存储的
	//00000000000000000000000001111110	-整型提升后

	//a + b = 00000000000000000000000010000011
	//10000001 -c
	//11111111111111111111111110000011	-c补码 -整型提升
	//11111111111111111111111110000010	-c反码
	//10000000000000000000000001111101	-c原码 -125

	char c = a + b;
	//使用整型输出字符c
	printf("%d", c);
}

简单的整型提升题:

char a = 0xb6;
short = 0xb600;
int c = 0xb6000000;

if(a == 0xb6){
	printf("a");
}
if(short == 0xb600){
	printf("b");
}
if(c == 0xb6000000){
	printf("c");
}
//输出:c

因为char和short都不是整型都要进行相应的整型提升数值就变了。

12.3算数转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另一个操作数的类型,否则操作将无法进行。下面的层次体系称为寻常算数转换

long double

double

float

unsigned long int

long int

unsigned int

int

如果某个操作数的类型再上面这个列表中排名较低,那么首先要转换为另一个操作数的类型后执行运算。(比如,一个int类型的与一个double类型的计算,int类型的会被转换为double类型进行计算)

警告:

但是算术转换要合理,要不然会有一些潜在的问题。

float f = 3.14;
int num = f;//隐式转换,会有精度丢失

函数的调用先后顺序无法通过操作符的优先级确定。

即使知道操作符的优先级和结构性也可能无法确定一个函数的唯一计算路径。

问题代码

int fun(){
    static int count = 1;
  	return ++count;
}

int main(){
    int answer;
    //		  1		2	  3
    //		  2		3	  1
    //		  3		2	  1
    //...等等·
    answer = fun()-fun()*fun();
    printf("%d",answer);
    return 0;
}

上述代码的运算符优先级可以判断,但其实函数调用的顺序是不确定的,虽然运算符优先级明确但是函数调用的顺序是随机的。

问题代码

int main(){
    int a = 1;
    int b = (++a) + (++a) + (++a);
    printf("%d",b);
    
    return 0;
}

上述代码的结果也并非是所想的9,10,12等。不同的编译器运行结果不一样。

**总结:**我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的。

的类型,那么除非其中一个操作数转换为另一个操作数的类型,否则操作将无法进行。下面的层次体系称为寻常算数转换

long double

double

float

unsigned long int

long int

unsigned int

int

如果某个操作数的类型再上面这个列表中排名较低,那么首先要转换为另一个操作数的类型后执行运算。(比如,一个int类型的与一个double类型的计算,int类型的会被转换为double类型进行计算)

警告:

但是算术转换要合理,要不然会有一些潜在的问题。

float f = 3.14;
int num = f;//隐式转换,会有精度丢失

函数的调用先后顺序无法通过操作符的优先级确定。

即使知道操作符的优先级和结构性也可能无法确定一个函数的唯一计算路径。

问题代码

int fun(){
    static int count = 1;
  	return ++count;
}

int main(){
    int answer;
    //		  1		2	  3
    //		  2		3	  1
    //		  3		2	  1
    //...等等·
    answer = fun()-fun()*fun();
    printf("%d",answer);
    return 0;
}

上述代码的运算符优先级可以判断,但其实函数调用的顺序是不确定的,虽然运算符优先级明确但是函数调用的顺序是随机的。

问题代码

int main(){
    int a = 1;
    int b = (++a) + (++a) + (++a);
    printf("%d",b);
    
    return 0;
}

上述代码的结果也并非是所想的9,10,12等。不同的编译器运行结果不一样。

**总结:**我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的。

表达式不必要复合繁琐,要明确目的,写一步看一步。

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

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

相关文章

使用WSL在Windows上安装Linux

文章目录 环境步骤参考 注&#xff1a;WSL是“Windows Subsystem for Linux”的缩写&#xff0c;即“适用于 Linux 的 Windows 子系统”&#xff0c;说白了就是在Windows系统里直接使用Linux&#xff0c;而不需要VMWare等虚拟软件。 环境 Windows 11 家庭中文版 步骤 首先&…

DORIS - DORIS简介

前言 本博文基于DORIS的2.1.5版本。apache-doris-2.1.5-bin-x64.tar.gz 是什么&#xff1f; DORIS官网 Apache Doris 是一款基于 MPP 架构的高性能、实时的分析型数据库&#xff0c;以高效、简单、统一的特点被人们所熟知&#xff0c;仅需亚秒级响应时间即可返回海量数据下的…

迅为2K1000开发板流畅运行Busybox、Buildroot、Loognix、QT5.12 系统

硬件配置 国产龙芯处理器&#xff0c;双核64位系统&#xff0c;板载2G DDR3内存&#xff0c;流畅运行Busybox、Buildroot、Loognix、QT5.12 系统! 接口全板载4路USB HOST、2路千兆以太网、2路UART、2路CAN总线、Mini PCIE、SATA固态盘接口、4G接口、GPS接口WIF1、蓝牙、Mini HD…

leetcode72. 编辑距离,二维动态规划

leetcode72. 编辑距离 给你两个单词 word1 和 word2&#xff0c; 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作&#xff1a; 1.插入一个字符 2.删除一个字符 3.替换一个字符 示例 1&#xff1a; 输入&#xff1a;word1 “horse”,…

nvm使用详解

在开发时采用nodejs环境的时候有时会遇见版本过新项目不匹配的情况这时的话重新下载过于麻烦,一个项目一个开发环境肯定不现实 这时我推荐一款nodejs管理器nvm 官网如下nvm文档手册 - nvm是一个nodejs版本管理工具 - nvm中文网NVM中文网:nvm一个nodejs的版本管理工具,为wind…

使用docker file创建镜像(thirty-seven day)

回顾&#xff1a;根据镜像创建容器 docker -it --name c0 centos:latest /bin/bash安装应用ctrlpqdocker export -o centos.tar c0docker import -m "山不像我走来&#xff0c;我便向山走去" centos.tar centos:httpddocker commit c0 centos:v2 一、docker file应…

Oracle 客户端 PL/SQL Developer 15.0.4 安装与使用

目录 官网下载与安装 切换中文与注册 连接Oracle数据库 tnsnames.ora 文件使用 Oracle 客户端 PL/SQL Developer 12.0.7 安装、数据导出、Oracle 执行/解释计划、for update。 官网下载与安装 1、官网&#xff1a;https://www.allroundautomations.com/products/pl-sql-d…

uni-app 微信小程序开发安装配置 HbuilderX 微信小程序开发工具

安装HbuilderX 官网下载&#xff1a; https://www.dcloud.io/hbuilderx.html 编译器用来编写小程序代码 微信小程序开发工具 官网下载&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html 用于小程序的页面调试 创建项目 HbuilderX创建项目…

找单身狗(c语言)

1./找单身狗 //在一个数组中只有两个数字出现一次&#xff0c;其他所以数字都出现了两次 //编写一个函数找出这两个只出现一次的数字 2.方法一&#xff1a;暴力求解&#xff0c;我们用冒泡函数&#xff0c;进行比较如果ij,那么n&#xff0c;如果n1,那么我们将他存储在arr2[]&a…

C++编程语言——基础设施:指针,数组和引用

指针&#xff0c;数组和引用 (Pointers, Arrays, and References) 目录 7.1 引言 7.2 指针 7.2.1 void* 指针 7.2.2 nullptr 指针 7.3 数组 7.3.1 数组初始化 7.3.2 字符串文字量 7.3.2.1 原字符串(Raw Character Strings) 7.3.2.2 大字符集(Larger Charac…

Multi-UAV|多无人机、多场景路径规划MATLAB

无人机(Unmanned Aerial Vehicle&#xff0c;UAV) 是一种无需机载驾驶员的半自主飞行器&#xff0c;由于其灵活度高、机动性强等特点&#xff0c;目前已广泛应用于民用和军用领域&#xff0c;如救援、农业、 输电线路巡检等。但在实际应用中&#xff0c;单个UAV难以应对任务点分…

看github源码必备的chrome插件

Web Activity Time Tracker 一个记录github等各个网站的阅读时长 长这样 GitHub Web IDE 一个方便打开github的各种web IDE&#xff0c;最后一个选项Clone in VScode 一键克隆到本地并打开非常省事 Elmo Chat - Your AI Web Copilot 一键总结项目内容&#xff0c;打开web i…

Datawhale X 李宏毅苹果书 AI夏令营 入门 Task2-了解线性模型

目录 线性模型分段线性曲线模型变形 线性模型 输入的特征 x 乘上一个权重&#xff0c;再加上一个偏置就得到预测的结果&#xff0c;这样的模型称为线性模型。 分段线性曲线 线性模型有很大的限制&#xff0c;这一种来自于模型的限制称为模型的偏差&#xff0c;无法模拟真实的…

网络压缩之参数量化(parameter quantization)

参数量化&#xff08;parameter quantization&#xff09;。参数量化是说能否只 用比较少的空间来储存一个参数。举个例子&#xff0c;现在存一个参数的时候可能是用64位或32位。 可能不需要这么高的精度&#xff0c;用16或8位就够了。所以参数量化最简单的做法就是&#xff0c…

智慧党建解决方案

1. 新时代党建工作背景 报告强调了新时代党建工作的重要性&#xff0c;提出要利用互联网、大数据等新兴技术推进智慧党建&#xff0c;提高党的执政能力和领导水平。 2. 基层党组织建设挑战 基层党组织在日常工作中面临组织管理难、过程监管难、宣传教育难等问题&#xff0c;…

基于yolov8的人头计数检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv8的人头计数检测系统是一种利用深度学习技术的先进解决方案&#xff0c;旨在实现高效、准确的人头计数功能。该系统以YOLOv8为核心算法&#xff0c;该算法是YOLO系列中的最新迭代&#xff0c;以其卓越的实时检测性能和准确性著称。 该系统通过复杂的网…

pip+代理

在cmd中使用代理时执行pip指令下载包时&#xff0c; 会报错 WARNING: Retrying (Retry(total4, connectNone, readNone, redirectNone, statusNone)) after connection broken by SSLError(SSLEOFError(8, EOF occurred in violation of protocol (_ssl.c:1131))): /simple/op…

day-45 全排列 II

思路 与上一题思路相同&#xff0c;代码也基本一致&#xff0c;只是需要全排列不重复 解题过程 可以利用Arrays.sort()函数将nums数组进行排序&#xff0c;这样相同的全排列数字的位置也会相同&#xff0c;可以利用List的contains()函数进行判断&#xff0c;如果不重复则加入答…

【CSS】border-image 样式不生效 - 和谷歌浏览器版本有关系 - 谷歌 80 版本边框图片样式失效问题

目录 问题解决 问题 使用边框图片时&#xff0c;部分谷歌浏览器版本中边框图片不生效 边框图片样式代码 border-image-source: url(img/dialog-bg.40ddf10d.png); border-image-slice: var(--topSlice) 50 var(--bottomSlice) 330; border-image-repeat: stretch; border-im…

Vulnhub靶场 | DC系列 - DC7

文章目录 DC-7环境搭建渗透测试 DC-7 环境搭建 靶机镜像下载地址&#xff1a;https://vulnhub.com/entry/dc-6,315/需要将靶机和 kali 攻击机放在同一个局域网里&#xff1b;本实验kali 的 IP 地址&#xff1a;192.168.10.146。 渗透测试 使用 nmap 扫描 192.168.10.0/24 网…