C语言操作符详解学习笔记

1. 操作符分类

算术操作符
移位操作符
位操作符
赋值操作符
单目操作符
关系操作符
逻辑操作符
条件操作符
逗号表达式
下标引用、函数调用和结构成员

2. 算术操作符

算术操作符:+ - * / %
“%”操作符的两侧数字必须为整数,其余操作符的两侧数字既可以是整数,也可以是浮点数。“/”两侧的数字都为整数时,执行整数除法,否则执行浮点数除法。

int main()
{
	int a = 3 / 5;   //整数除法
	float b = 3.0 / 5;   //浮点数除法
	float c = 3.0 / 5.0;   //浮点数除法
	printf("%d %f %f", a, b, c);
	return 0;
}

3. 移位操作符

① << :左移操作符,二进制序列左移一位,左边丢弃,右边补0;
②>>:右移操作符分为算术右移和逻辑右移。算术右移:二进制序列右移一位,右边丢弃,左边补原符号位;逻辑右移:二进制序列右移一位,右边丢弃,左边补0。

int main()
{
	int a = 5;  //...00000101
	int b = a << 1;  //...00001010
	printf("%d\n", b);

	int c = -1;  //...11111111
	int d = c >> 1;    //算术右移:补1,...11111111     逻辑右移:补0,0...11111111
	printf("算术右移:%d\n", d);
	return 0;
}

警告:对于移位操作符不能移动负数位,这个标准是未定义的。(a<<-1)

4. 位操作符

&:按位与,将二进制序列按位进行与操作得到新序列(包括符号位)
|:按位或,将二进制序列按位进行或操作得到新序列(包括符号位)
^:按位异或(相同为0,不同为1),将二进制序列按位进行异或操作得到新序列(包括符号位)

int main()
{
	int a = 1;
	int b = 5;
	printf("%d\n", a&b);   //输出:1
	printf("%d\n", a|b);   //输出:5
	printf("%d\n", a^b);   //输出:4

	int c = -1;
	int d = 5;
	printf("%d\n", c&d);   //输出:5
	printf("%d\n", c | d);   //输出:-1
	printf("%d\n", c^d);   //输出:-6
	return 0;
}

如何不创建临时变量,来交换两个数的值?(通过异或操作符实现)

int main()
{
	int a = 5;
	int b = 3;
	printf("%d  %d\n", a, b);
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("%d  %d\n", a, b);
}

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

int main()
{
	int a = 13;
	int b = 1;
	int count = 0;
	for(int i=0;i<32;i++)
	{
		count += a & b;
		a = a >> 1;
	}
	printf("%d\n", count);
	return 0;
}

将二进制数5的第四位置1。

int main()
{
	int a = 5;
	int b = 1;
	a = a | (b << 4 - 1);
	printf("%d\n", a);
	return 0;
}

将二进制数5的第三位置0。

int main()
{
	int a = 13;
	int b = 1;
	a = a ^ (b << 3 - 1);
	printf("%d\n", a);
	return 0;
}

5. 赋值操作符

=:
复合赋值运算符:
①+=:
②-+:
③*=:
④/=:
⑤>>=:
⑥<<=:
⑦&=:
⑧|=:
⑨^= :

6. 单目运算符

!:逻辑反操作
-:负值
+:正值
&:取地址
sizeof:操作数的类型长度
~:对一个二进制数按位取反(包括符号位)
++:前置、后置++
—:前置、后置—
*:间接访问操作符(解引用操作符)
(类型):强制类型转换

6.1 sizeof

int main()
{
	int a = 0;
	int arr[10] = { 0 };
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(int));

	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof(int [10]));

	short s = 5;
	int b = 10;
	printf("%d\n", sizeof(s = b + 2));    //输出为2,sizeof括号内放的表达式不参与运算
	printf("%d\n", s);    //输出为5
}

6.2 sizeof和数组

void test1(int arr[])
{
	printf("%d \n", sizeof(arr));  //输出为4或者8
}

void test2(char ch[])
{
	printf("%d \n", sizeof(ch));  //输出为4或者8
}

int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("%d \n", sizeof(arr));   //输出为40
	printf("%d \n", sizeof(ch));   //输出为10
	test1(arr);
	test2(ch);
	return 0;
}

为什么调用函数内部的输出为4或者8呢?因为当数组作为参数调用函数时,实际上传输过去的值为数组首元素的地址。所以在函数内部,实际上是创建了一个指针用来接收传递过来的地址,因此此处的输出为4或者8。(32位系统输出4,64位输出8)

7. 关系操作符

①>:
②>=:
③<:
④<=:
⑤!=:
⑥==:

8. 逻辑操作符

逻辑与:&&
逻辑或:||

360面试题

int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;   //将a换成1再计算一遍
	i = a++ && ++b && d++;
	//a=0时,输出为  1,2,3,4   (当a=0时,0与任何数相与都为0,因此系统不会再计算后面的表达式了)
	//a=1时,输出为  2,3,3,5
	
	//i = a++ || ++b || d++;
	//a=1时,输出为  2,2,3,4   (当a=1时,1与任何数进行逻辑或运算都为1,因此系统不会再计算后面的表达式了)
	//a=0时,输出为  1,3,3,4
	
	printf("%d  %d  %d  %d  \n", a, b, c, d);
	return 0;
}

9. 条件操作符

b = (a > b ? 1 : 2);
//a>b为真,则b=1
//a>b为假,则b=2

10. 逗号表达式

逗号表达式:从左向右依次计算,但是整个表达式的结果是最后一个表达式的值

int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);  //逗号表达式,c为13


if (a =b + 1, c=a / 2, d > 0)   //最后一个表达式是if语句的条件


a = get_val();
count_val(a);
while (a > 0)
{
	a = get_val();
    count_val(a);
}
//如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a>0)
{
        ;
}

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

11.1 下标引用操作符

int arr[10];   //创建数组
arr[9] = 10;  //使用下标引用操作符。
//[ ]的两个操作数是arr和9。

11.2 函数调用操作符

int add(int x, int y)
{
	return x + y;
}

int main()
{
	int a = 3;
	int b = 4;
	int c = add(a, b);  //使用()作为函数调用操作符,add、a、b都是()的操作数。
	printf("%d\n",c );
	return 0;
}

11.3 访问一个结构体成员

详情浏览链接第2部分

12 表达式求值

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

12.1 隐式类型转换

C的整型算术运算总是以缺省整型类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
所以是如何进行整型提升的呢?①负数的整型提升:高位补1;②正数的整型提升,高位补0;③无符号整型提升,高位补0。

int main()
{
	char a = 3;
	//00000011
	//整形提升:0000000 00000000 00000000 000000011

	char b = 127;
	//01111111
	//整形提升:00000000 00000000 00000000 01111111

	char c = a + b;
	//相加:00000000 00000000 00000000 10000010
	//截断存入c中,c:10000010
	
	printf("%d\n", c);	//-126
	//由于输出的类型为整型,所以对c进行整型提升
	//整形提升:11111111 11111111 11111111 10000010(补码)
	//反码:11111111 11111111 11111111 10000001
	//原码:10000000 00000000 00000000 01111110
	return 0;
}

实例1:

int main()
{
	char a = 0xb6;
	short b = 0xb600;
 	int c = 0xb6000000;
	if(a==0xb6)   //将a整型提升后a变为负值
		printf("a");
 	if(b==0xb600)   //将b整型提升后a变为负值
		printf("b");
 	if(c==0xb6000000)   //c不需要进行整型提升,输出结果为c
 		printf("c");
	return 0;
}

实例2:

	int main()
	{
		char c = 1;
		printf("%u\n", sizeof(c));   //输出为1
		printf("%u\n", sizeof(+c));   //输出为4,c需要进行表达式运算,所以此处进行了整型提升
		printf("%u\n", sizeof(-c));   //输出为4,c需要进行表达式运算,所以此处进行了整型提升
		return 0;
	}

12.2 算术转换

当表达式的操作符各个类型不同的话,则需要先将它们转化为同一类型的值再进行计算。

由低向高转换
long double
double
float
unsigned long int
long int
unsigned int
int

12.3 操作符的属性

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

  1. 操作符的优先级;
  2. 操作符的结合性;
  3. 是否控制求值顺序。(逻辑与、逻辑或、三目运算符、逗号表达式)
    总结:我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的。

1.一个表达式有值属性和类型属性两个属性。

该笔记是学习了B站up主:鹏哥C语言 的课程所写。课程传送门

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浮沉丿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值