IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 初学C语言之操作符详解 -> 正文阅读

[C++知识库]初学C语言之操作符详解

目录

算术操作符

+运算

-运算

*运算

/运算

%运算

移位操作符

<<左移位

正数移位

负数移位

>>右移位

位操作符

&按位与

|按位或

^按位异或

位运算符练习

赋值操作符

=赋值操作符

+=,-=,*=,/=,%=,>>=,<<=,&=,|=,^=复合赋值操作符

单目操作符

!逻辑反操作

-负值操作

+正值操作

&取地址操作

sizeof计算类型大小操作

~二进制取反操作

--前置

--后置

++前置

++后置

*解引用操作

(类型)强制类型转换操作

sizeof和数组

关系操作符

>,>=,<,<=,!=,==

逻辑操作符

&&逻辑与操作(并且)

||逻辑或操作(或者)

练习?

条件操作符

?:条件操作

逗号表达式

下标引用操作符

[]下标引用操作

函数调用操作符

()函数调用操作

结构成员操作符

.结构体.成员名操作

->结构体指针->成员名操作

表达式求值

隐式类型转换

算术转换

操作符的属性

算术操作符

+运算

-运算

*运算

/运算

整数/运算

当a/b,且a,b都是整型时,得到的结果是整型。

int main()
{
	int a = 7, b = 2;
	int c = a / b;
	printf("%d\n", c);
	a = 7;
	system("pause");
	return 0;
}

浮点数/运算

当a/b,且a,b中任一浮点型时,得到的结果是浮点型。

int main()
{
	int a = 7;
	float b = 2.0;
	float c = a / b;
	printf("%f\n", c);
	a = 7;
	system("pause");
	return 0;
}

%运算

a%b,a与b必须是整数,其余算术运算符没有这个要求。

a%b的结果是余数。

int main()
{
	int a = 7, b = 2;
	int c = a%b;
	printf("%d", c);
	system("pause");
	return 0;
}

移位操作符

位移操作符移动的是二进制位,操作符的两边必须是整数。

在计算机中由0和1组成的数字就是2进制,原理与10进制相同

十进制123100203
1*10的平方2*10的1次方3*10的0次方
二进制7(111)421
1*2的平方1*2的1次方1*2的0次方

二进制位在内存中的存储是以补码的形式,其最高位表示符号位(0位正,1为负),那么什么是补码?

正数与0的补码:

以10为例:

原码:0000 0000 0000 0000 0000 0000 0000 1010

反码:0000 0000 0000 0000 0000 0000 0000 1010

补码:0000 0000 0000 0000 0000 0000 0000 1010

整数与0的原码、反码、补码是相同的。

负数

以-10为例:

原码:1000 0000 0000 0000 0000 0000 0000 1010

反码:1111 1111?1111 1111?1111 1111?1111 0101? ? ? ?原码除符号位外取反。

补码:1111 1111?1111 1111?1111 1111?1111 0110? ? ? ?反码+1

<<左移位

位移规则:数字最左边的位抛弃,右边补0。

正数移位

以10为例,向左移动1位。

10的补码:0000 0000 0000 0000 0000 0000 0000 1010

向左移动:0000 0000 0000 0000 0000 0000 0001 0100

移动后结果为20。
int main()
{
	int a = 10;
	printf("%d", a << 1);
	system("pause");
	return 0;
}
以20为例,向左移动1位。

20的补码:0000 0000 0000 0000 0000 0000 0001 0100

向左移动:0000 0000 0000 0000 0000 0000 0010 1000

移动后结果为40。
int main()
{
	int a = 20;
	printf("%d", a << 1);
	system("pause");
	return 0;
}
以15为例,向左移动1位。

15的补码:0000 0000 0000 0000 0000 0000 0000 1111

向左移动:0000 0000 0000 0000 0000 0000 0001 1110

移动后结果位30。
int main()
{
	int a = 15;
	printf("%d", a << 1);
	system("pause");
	return 0;
}

负数移位

以-10为例

-10的补码:1111 1111?1111 1111?1111 1111?1111 0110?

? 左移一位:1111 1111?1111 1111?1111 1111?1110 1100?

移动后结果为-20。
以-20为例

-20的补码:1111 1111?1111 1111?1111 1111?1110 1100??

? 左移一位:1111 1111?1111 1111?1111 1111?1101 1000?

移动后结果为-40。

>>右移位

右移操作符分为逻辑右移和算术右移,两种操作符的使用取决于编译器。

逻辑右移的规则:位的左边填充0,右边丢弃。

算术右移的规则:位的左边使用符号位填充,右边丢弃。

以-10为例

-10的补码:1111 1111?1111 1111?1111 1111?1111 0110?

? 右移一位:1111 1111?1111 1111?1111 1111?1111 1011?

移动后结果为-5。
以10为例,向右移动1位。

10的补码:0000 0000 0000 0000 0000 0000 0000 1010

向右移动:0000 0000 0000 0000 0000 0000 0000 0101

移动后结果为5。

左移和右移在不超过位的范围的情况下,相当于乘以2和除以2。

注意:在使用位运算的时候,不能使用负数作为位数,这个是标准未定义的。

位操作符

&按位与

规则:当两个数按位与,相同的位数只要有一个为0,该位的结果就为0。

以3&5为例

3的补码:0000 0000 0000 0000 0000 0000 0000 0011
5的补码:0000 0000 0000 0000 0000 0000 0000 0101
3&5补码: 0000 0000 0000 0000 0000 0000 0000 0001
结果为1。
int main()
{
	printf("%d", 3 & 5);
	system("pause");
	return 0;
}

|按位或

规则:当两个数按位或,相同的位数只要有一个为1,该位的结果就为1。

以3|5为例

3的补码:0000 0000 0000 0000 0000 0000 0000 0011
5的补码:0000 0000 0000 0000 0000 0000 0000 0101
3|5补码: 0000 0000 0000 0000 0000 0000 0000 0111
结果为7。
int main()
{
	printf("%d", 3 | 5);
	system("pause");
	return 0;
}

^按位异或

规则:当两个数按位异或,相同的位数数字不同结果为1,数字相同结果为0。

以3^5为例

3的补码:0000 0000 0000 0000 0000 0000 0000 0011
5的补码:0000 0000 0000 0000 0000 0000 0000 0101
3^5补码: 0000 0000 0000 0000 0000 0000 0000 0110
结果为6。
int main()
{
	printf("%d", 3 ^ 5);
	system("pause");
	return 0;
}

位运算符练习

1、不能创建临时变量,实现两个数的交换。

先看一组推论。

3的补码: 0000 0000 0000 0000 0000 0000 0000 0011
3的补码: 0000 0000 0000 0000 0000 0000 0000 0011
3^3补码: 0000 0000 0000 0000 0000 0000 0000 0000

3^3补码: 0000 0000 0000 0000 0000 0000 0000 0000
5的补码: 0000 0000 0000 0000 0000 0000 0000 0101
异或补码:0000 0000 0000 0000 0000 0000 0000 0101
结果为5,由此可知,3异或3的结果为0,0异或5的结果为5
推广,同一个数异或结果为0,0与任何数异或结果为任何数


使用交换律
3的补码: 0000 0000 0000 0000 0000 0000 0000 0011
5的补码: 0000 0000 0000 0000 0000 0000 0000 0101
3^5补码: 0000 0000 0000 0000 0000 0000 0000 0110

3^5补码: 0000 0000 0000 0000 0000 0000 0000 0110
3的补码: 0000 0000 0000 0000 0000 0000 0000 0011
异或补码:0000 0000 0000 0000 0000 0000 0000 0101
结果为5,由此可知异或支持交换律。

既然^运算符支持交换律,那么可以推导出下面的公式。

a=3,b=5
a=a^b;此时a的结果为a^b
b=a^b;b的结果为a^b^b=a,所以b已经保存原本a的值
a=a^b;a的结果为a^b^a=b,此时b保存的是原来a的值,所以a的结果是原来b的值

int main()
{
	int a = 3;
	int b = 5;
	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);
	system("pause");
	return 0;
}

不适用第三个变量也可以使用加法运算进行求解。

int main()
{
	int a = 3, b = 5;
	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);
	system("pause");
	return 0;
}

?但这样的方法有个问题,就是在数字很大的时候容易溢出,并且效率也不够高,所以在交换的时候最好用的还是使用第三个变量进行交换。

2、求一个整数存储在内存中的二进制中1的个数。

思路1,余2法,num余2的结果为1,说明num在二进制的最右边的值为1,之后除以2在某种程度上可以看成是右移一位.因此只要不断的除以2,直到0为止,就可以找到num中所有的1.


int main()
{
    int num=7;
    int count=0;
    while(num)
    {
        if(num%2==1)
        {
            count++;
        }
        num/=2;
    }
    return 0;
}
但这这个方法有个问题,就是当num为负数时,num%2的结果为-1,所以不能使用。
思路2移位法,就是1从前进0步开始直到前进到32-1步为止,每前进一次都要与一次,如果结果为1则count++,如果为0则count不++

int main()
{
	int num = 7;
	int i = 0;
	int count = 0;
	for (i = 0; i <32; i++)
	{
		if (num&(1 << i))
		{
			count++;
		}
	}
	printf("%d", count);
	system("pause");
	return 0;
}
这种方法每个数必须循环32次浪费时间。
思路3拆数法,任意不为0的数,一定表示有1的存在,所以可以用这个数与比比它小以的数,比它小一的数表示拆掉了这个数的最低为

以7为例

2个1
5的补码  0000 0000 0000 0000 0000 0000 0000 0101
4的补码  0000 0000 0000 0000 0000 0000 0000 0100
5&4补码  0000 0000 0000 0000 0000 0000 0000 0100
剩余1个1

1个1
4的补码  0000 0000 0000 0000 0000 0000 0000 0100
3的补码  0000 0000 0000 0000 0000 0000 0000 0011
4&3补码  0000 0000 0000 0000 0000 0000 0000 0000
剩余0

int main()
{
	int num = 100;
	int count = 0;
	while (num)
	{
		count++;
		num = num&(num - 1);
	}
	printf("%d", count);
	system("pause");
	return 0;
}

赋值操作符

=赋值操作符

+=,-=,*=,/=,%=,>>=,<<=,&=,|=,^=复合赋值操作符

单目操作符

!逻辑反操作

规则将真变成假,假变成真(C语言中0为假,非0为真)

当num为真时进入if
int main()
{
	int num = -100;
	int count = 1;
	if (num)
	{
		printf("%d", count);
	}
	system("pause");
	return 0;
}

当num为假时进入if
int main()
{
	int num = 0;
	int count = 1;
	if (!num)
	{
		printf("%d", count);
	}
	system("pause");
	return 0;
}

-负值操作

规则改变一个数的符号(正负转换)

int main()
{
	int num = 10;
	num = -num;
	printf("%d\n", num);
	num = -num;
	printf("%d\n", num);
	system("pause");
	return 0;
}

+正值操作

没有任何意义的操作。

&取地址操作

a变量是整型,在内存中占有4个字节,&取地址运算符取出的是第一个字节的地址,上面的图片代码化是int *p=&a;含义是将a的首字节的地址取出,并放入类型为(int *)的指针变量p中;

sizeof计算类型大小操作

规则计算一个数据类型所占内存空间的大小,单位是字节,表达式可以是整型,类型等等不能是函数哦。

int main()
{
	int num = 10;
	printf("%d\n", sizeof(int [10]));
	printf("%d\n", sizeof(int*));
	system("pause");
	return 0;
}

~二进制取反操作

规则:二进制按位取反是指将一个数的每一位取反,0变1,1变0,注意该操作符只能作用于整型。

int main()
{
	int a = 1;
	printf("%d", ~a);
	system("pause");
	return 0;
}



1的补码: 0000 0000 0000 0000 0000 0000 0000 0001
取反补码:1111 1111 1111 1111 1111 1111 1111 1110

按照有符号类型读取
补码取反:1000 0000 0000 0000 0000 0000 0000 0001
反码加1:  1000 0000 0000 0000 0000 0000 0000 0010
结果为-2

无符号整型
取反补码:1111 1111 1111 1111 1111 1111 1111 1110
结果为4294967294

--前置

规则:先自减,后使用

--后置

规则:先使用,后自减

++前置

规则:先自增,后使用

++后置

规则:先使用,后自增

int main()
{
	int a = 3;
	int b = ++a;
	printf("%d\n", a);
	printf("%d\n", b);
	system("pause");
	return 0;
}
//代码结果为4 4说明a自增后才给b赋值。

int main()
{
	int a = 3;
	int b = a++;
	printf("%d\n", a);
	printf("%d\n", b);
	system("pause");
	return 0;
}
//代码结果为4 3说明a先赋值给b才自增。

*解引用操作

规则:解引用操作于指针变量一起使用,意义是通过指针变量中所保存的地址,找到对应的地址中存储的值。

?所以*p等于a。

int main()
{
	int a = 10;
	int *pa = &a;
	*pa = 20;
	printf("%d\n", a);
	system("pause");
	return 0;
}

(类型)强制类型转换操作

规则:将类型强制转换成()内的类型。

int main()
{
	float a = 10.6;
	printf("%d\n", (int)a);
	system("pause");
	return 0;
}

sizeof和数组

sizeof操作符计算类型的大小,但是计算要注意区分计算的类型具体是什么

void test(int arr[], char ch[])
{
	printf("2=%d\n", sizeof(arr));//2
	printf("4=%d\n", sizeof(ch));//4
}


int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("1=%d\n", sizeof(arr)); //1
	printf("3=%d\n", sizeof(ch));//3
	test(arr, ch);
	system("pause");
	return 0;
}

1的结果为40       计算的是数组的大小
2的结果为4或者8   计算的是指针的大小
3的结果为10       计算的是数组的大小
4的结果为4或者8    计算的是指针的大小

关系操作符

>,>=,<,<=,!=,==

规则:判断两个值大小或者等于,不等于关系的操作符。

注意:==容易于=混用。

逻辑操作符

&&逻辑与操作(并且)

规则:判断表达式的是否为真(C语言中0为假,非0为真),&&判断的是当两个值都为真时表达式的结果为真,若其中一个为假则表达式的值为假。

注意:&&的特性会控制表达式的求值顺序,也就是说a&&b,当a的值为0时b就不再计算。

int main()
{
	int a = 1;
	int b = 2;
	int c = 3;
	int d = 4;
	int i = a++&&++b&&d++;(1)
	printf("a=%d,b=%d,c=%d,d=%d\n", a, b, c, d);//(1)2 3 3 5
	a = 0;
	b = 2;
	c = 3;
	d = 4;
	i = a++&&++b&&d++;(2)
	printf("a=%d,b=%d,c=%d,d=%d\n", a, b, c, d);//(2)1 2 3 4
	a = 0;
	b = 2;
	c = 3;
	d = 4;
	i = ++a&&++b&&d++;(3)
	printf("a=%d,b=%d,c=%d,d=%d\n", a, b, c, d);//(3)1 3 3 5
	system("pause");
	return 0;
}

?(1)表达式,因为每一个数非0为真,没有促发短路运算,所以表达式中每个变量的值都被修改。

(2)表达式,虽然a++的结果为1,但因为后置++,先使用再自增,所以表达式中得到的值为0,促发短路运算,后面没有再计算。

(3)表达式,虽然a还是0,但前置++,a先进行了自增然后使用,所以表达式中的得到1,因此进行了后面的计算。

||逻辑或操作(或者)

规则:判断表达式的值的真假,a||b中,只要a或者b任意为真,整个表达式的值都为真。

注意:||会控制表达式的求值顺序,只要a为真,表达式的结果就为真,后面的不再计算。

int main()
{
	int a = 1;
	int b = 0;
	int c = 3;
	int d = 4;
	int i = a++||b++||d++;
	printf("a=%d,b=%d,c=%d,d=%d\n", a, b, c, d);//2 0 3 4
	a = 0;
	b = 2;
	c = 3;
	d = 4;
	i = a++||++b||d++;
	printf("a=%d,b=%d,c=%d,d=%d\n", a, b, c, d);//1 3 3 4
	a = 0;
	b = 2;
	c = 3;
	d = 4;
	i = ++a||++b||d++;
	printf("a=%d,b=%d,c=%d,d=%d\n", a, b, c, d);//1 2 3 4
	system("pause");
	return 0;
}

练习?

求1000到2000之间的闰年。

闰年的判断标准是能被4整除并且不能被100整除,或者能被400整除的数是闰年。

int main()
{
	int year = 0;
	for (year = 1000; year <= 2000; year += 4)
	{
		if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
		{
			printf("%d  ", year);
		}
	}
	system("pause");
	return 0;
}

条件操作符

?:条件操作

规则:? 表达式1?表达式2:表达式3,如果表达式1的值为真,那么计算表达式2的值并作为整个表达式的值,如果1为假,那么计算表达式3的值并作为整个表达式的值。

注意:控制表达式的运算顺序,表达式2和表达式3中只有一个被运行。

逗号表达式

规则:逗号表达式就是用逗号隔开的表达式(a,b,c),整个表达式从左向右依次执行,整个表达式的结果就是c的结果。

注意:逗号表达式控制求值顺序,如果前面的表达式没有赋值,那么将毫无意义。

逗号运算符简化代码
a = test();
fun(a);
while (a > 0)
{
	a = test();
	fun(a);
}


while (a = test(), fun(a), a > 0)
{

}

下标引用操作符

[]下标引用操作

规则:对数组进行操作,[]使用两个操作数,一个是数组名,一个是索引值

以arr[5]为例

arr[5]=*(arr+5);
因为加法交换律
*(arr+5)=*(5+arr);
*(5+arr)=5[arr];
int main()
{
	int arr[10] = {0};
	5[arr] = 7;
	printf("%d", arr[5]);
	system("pause");
	return 0;
}

函数调用操作符

()函数调用操作

规则:函数调用操作符用来调用函数,最少可以有一个操作符。

结构成员操作符

.结构体.成员名操作

->结构体指针->成员名操作

上面两个操作符都是对结构体进行操作。

struct stu
{
	int num;
	int num2;
};


void init(struct stu* ps)
{
	ps->num = 10;
	ps->num2 = 20;
}

print(struct stu* ps)
{
	printf("%d\n", (*ps).num);
	printf("%d\n", (*ps).num2);
}

int main()
{
	struct stu s = { 0 };
	init(&s);
	print(&s);
	system("pause");
	return 0;
}

表达式求值

表达式求值的操作顺序一部分是由优先级和结合性确定,同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。

隐式类型转换

C的整型算术运算总是至少以缺省(默认)整型类型的精度来进行的,为了获得这个精度,表达式中的短整型和字符类型操作数在使用前被转换为普通类型,这个转换称为整型提升。

整型提升的意义:CPU内整型运算器(ALU)的操作数字节长度一般就是int的字节长度。

举例:

char a,b,c;

c=a+b;

首先a与b进行整型提升,提升到int类型,然后进行加法运算,运算完以后结果进行截断,存入c中。

整型提升的规则:按照变量的数据类型的符号位来进行提升。

char c=-1;
一、将-1放入c中
  -1的补码:1111 1111 1111 1111 1111 1111 1111 1111
截断放入c中:1111 1111
二、使用时将-1从c中取出
  -1的补码:1111 1111
  整型提升:1111 1111 1111 1111 1111 1111 1111 1111


char c=1;
一、将1放入c中
   1的补码:0000 0000 0000 0000 0000 0000 0000 0001
截断放入c中:0000 0001
二、使用时将1从c中取出
   1的补码:0000 0001
  整型提升:0000 0000 0000 0000 0000 0000 0000 0001
无符号与正数的整型提升相同,前面补0
整型提升的计算

int main()
{
	char a = 5;
	char b = 126;
	char c = 0;
	c = a + b;
	printf("%d\n", c);
	system("pause");
	return 0;
}

char a = 5;
5的补码:   0000 0000 0000 0000 0000 0000 0000 0101
存入a中:  0000 0101
char b = 126;
126的补码:0000 0000 0000 0000 0000 0000 0111 1110
存入b中:  0111 1110
char c = 0;
0的补码:  0000 0000 0000 0000 0000 0000 0000 0101
存入c中:  0000 0000
c=a+b;
a提升:    0000 0000 0000 0000 0000 0000 0000 0101
b提升:    0000 0000 0000 0000 0000 0000 0111 1110
 a+b:      0000 0000 0000 0000 0000 0000 1000 0011
截断存入:  1000 0011
printf("%d\n", c);按照有符号整型打印
整型提升得到c的补码:  1111 1111 1111 1111 1111 1111 1000 0011
补码取反:            1000 0000 0000 0000 0000 0000 0111 1100
反码加一:            1000 0000 0000 0000 0000 0000 0111 1101   结果-125
                      
举例2
int main()
{
	char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;
	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)
		printf("c");
	system("pause");
	return 0;
}
代码运行结果是c;
运行过程;
0xb6的二进制:1011 0110(182)
a == 0xb6
整型提升:1111 1111 1111 1111 1111 1111 1011 0110
补码减一:1111 1111 1111 1111 1111 1111 1011 0101
取反   :1000 0000 0000 0000 0000 0000 0100 1010(-74)
0xb6常量的值为182,表达式中a的值为-74所以不相等。

0xb600的二进制:1011 0110 0000 0000(46592)
b == 0xb600
整型提升:1111 1111 1111 1111 1011 0110 0000 0000
补码减一:1111 1111 1111 1111 1011 0101 1111 1111
取反   :1000 0000 0000 0000 0100 1010 0000 0000(-18944)
0xb600常量的值为46592,表达式中b的值为-18944所以不相等。

0xb6000000的二进制:1011 0110 0000 0000 0000 0000 0000 0000
c == 0xb6000000
不使用整型提升:1011 0110 0000 0000 0000 0000 0000 0000
补码减一:     1011 0101 1111 1111 1111 1111 1111 1111 
取反:         1100 1010 0000 0000 0000 0000 0000 0000(-1241513984)

如果想让三个表达式成立,整型提升时要注意类型,不能是有符号的类型。
int main()
{
	unsigned char a = 0xb6;
	unsigned short b = 0xb600;
	int c = 0xb6000000;
	char d = 0;
	if (a == 0xb6)
		printf("a\n");
	if (b == 0xb600)
		printf("b\n");
	if (c == 0xb6000000)
		printf("c\n");
	system("pause");
	return 0;
}
举例3
int main()
{
	char c = -1;
	printf("%u\n", sizeof(c));
	printf("%u\n", sizeof(+c));
	printf("%u\n", sizeof(-c));
	system("pause");
	return 0;
}
代码运行的结果为1,4,4,说明+c与-c在计算时进行了整型提升,此时的类型为int,所以结果为4

算术转换

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

long double
double
float
unsigfned long int
long int
unsigned int
int

如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。

注意:算术转换要合理,否则会存在一些潜在的问题

float f=3.14;
int num=f;
num的值为3.

操作符的属性

复杂的表达式求值有三个影响的因素。

1、操作符的优先级。

2、操作符的结合性。

3、是否控制求值顺序。

优先级:两个相邻操作符之间谁先计算。

结合性:当两个相邻的操作符优先级相同时,计算就看结合性是从左向右,还是从右向左。

影响求值顺序;部分操作符求值时,会影响表达式计算的顺序。

运算符表:

在这里插入图片描述

一些问题的表达式

表达式1
a*b+c*d+e*f
求值顺序

*与+相邻时,*的优先级高     
一、a * b + c * d + e * f 
      1   4   2   5   3

二、a * b + c * d + e * f 
      1   3   2   5   4
优先级只能决定相邻的*和+时*的运算先于+,但不能决定最后一个*与第一个+的先后顺序。
表达式2
c + --c
--的优先级比+高,所以--先计算,但是并不能确定第一个c的值多久进行求值,可能在--c之前,也可能是在--c之后。
表达式3
int main()
{
	int i = 10;
	i = i-- - --i * (i = -3) * i++ + ++i;
	printf("%d\n", i);
	system("pause");
	return 0;
}
该代码在不同的编译器中结果不同。
代码4

int main()
{
	int i = 1;
	i = ++i + ++i + ++i;
	printf("%d\n", i);
	system("pause");
	return 0;
}
VS下,结果为12;
运行顺序
i = ++i + ++i + ++i;
     1  4  2  5  3

linux下,结果为10
i = ++i + ++i + ++i;
     1  3  2  5  4
代码5
int fun()
{
	static int count = 1;
	return ++count;
}

int main()
{
	int answer;
	answer = fun() - fun()*fun();
	printf("%d\n", answer);
	system("pause");
	return 0;
}

VS下结果为-10;
运行顺序
 fun() - fun() * fun();
   1   5   2   4   3
但是在不同的编译器下运行的顺序有很多不同。

注意:如果表达式中不能确定唯一顺序,那个表达式就存在问题。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-24 20:38:18  更:2022-09-24 20:42:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 14:55:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码