C语言--操作符详解

本文详细介绍了C语言中的算数操作符,包括加、减、乘、除和取模,以及移位操作符的源码、反码、补码概念和左移、右移的区别。此外,还讨论了位操作符如按位与、按位异或、按位或和按位取反的用法和技巧。文章还涵盖了赋值操作符、复合操作符、单目操作符、关系操作符、逻辑操作符、条件操作符、逗号表达式、下标引用、函数调用和结构成员访问等内容,以及操作符的优先级、结合性和求值顺序的属性。
摘要由CSDN通过智能技术生成


前言

一、算数操作符

+、-、*、/、%

1.%操作符只能作用于整数
2.除了%操作符之外,其他的几个操作符可以作用于整数和浮点数
3./操作符 无浮点数,执行整数除法,有浮点数,执行浮点数除法

int main()
{
	double a = 5 / 2;    无浮点数,执行整数除法
	printf("%lf",a);
	return 0;
}
打印结果为2.000000
int main()
{
	double a = 5 / 2.0;    浮点数,执行浮点数除法
	printf("%lf",a);
	return 0;
}
打印结果为2.500000

二、移位操作符

源码反码补码

printf打印出来的值都是原码
正整数在内存中的存储是补码,正整数的源码反码补码都一样
负整数在内存中的存储是补码,负整数的源码反码补码不相同

负整数的第一位为符号位,1代表负数,0代表正数
a = -1
a的二进制序列
源码 10000000000000000000000000000001
除了符号位其他都反过来
反码 11111111111111111111111111111110
补码=反码+1
补码 11111111111111111111111111111111
打印结果为 -1

左移位<<、右移位>>

移动的是二进制位
都是以算数移动为主
以右移位为主,a = -1为例子

算数移动

算数左移:低位补0
算数右移:低位丢弃,高位补原符号位
printf(“%d”,a >> 1);
原码 10000000 00000000 00000000 00000001
反码 11111111 11111111 11111111 11111110
补码 11111111 11111111 11111111 11111111
a >> 1向右移动一位
11111111 11111111 11111111 111111111
打印结果仍为-1

逻辑移动

逻辑左移:低位补0
逻辑右移:高位补0
printf(“%d”,a >> 1);
原码 10000000 00000000 00000000 00000001
反码 11111111 11111111 11111111 11111110
补码 11111111 11111111 11111111 11111111
a >> 1向右移动一位
补码 01111111 11111111 11111111 11111111
反码 01111111 11111111 11111111 11111110
原码 00000000 00000000 00000000 00000001
打印结果为1

三、位操作符

它的操作数必须是整数
比较的是二进制位

按位与 &

两个同时为1才为1

int main()
{
	int a = 3;
	int b = 5;
	int c = a & b;
	printf("%d",c);
	return 0;
}
a的二进制序列    00000000000000000000000000000011    3
b的二进制序列    00000000000000000000000000000101    5
c的二进制序列    00000000000000000000000000000001    1
打印结果为1

使用技巧

1.任何变量 & 1 可以保留原本的数

int a = 20;
int b = a & 1;
b和a 的值相等

2.求一个数在内存中二进制中 1 的个数

if ((a >> i) & 1 == 1)
	count++;

按位异 |

两个有一个为1 就为 1

int main()
{
	int a = 3;
	int b = 5;
	int c = a | b;
	printf("%c",c);
	return 0;
}
a的二进制序列    00000000000000000000000000000011    3
b的二进制序列    00000000000000000000000000000101    5
c的二进制序列    00000000000000000000000000000111    7
打印结果为7

按位异或 ^

相同为0,相异为1

相同为0,相异为1
int main()
{
	int a = 3;
	int b = 5;
	int c = a ^ b;
	printf("%c",c);
	return 0;
}
a的二进制序列    00000000000000000000000000000011    3
b的二进制序列    00000000000000000000000000000101    5
c的二进制序列        00000000000000000000000000000110    6
打印结果为6

使用技巧

不创造第三个变量,实现两个数的交换

int main()
{
	int a = 3;
	int b = 5;
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	return 0;
}
a    011    110    110
b    101    101    011
^    110    011    101
三组数据可以互相推导

按位取反 ~

对一个数的二进制按位取反

int main()
{
	int a = 0;
	int b = ~a;
	printf("%d",b);
	return 0;
}
a的二进制序列    00000000000000000000000000000000
b的二进制序列    11111111111111111111111111111111
在内存中的存储是补码
反码 = 补码 -1       11111111111111111111111111111110
原码=反码按位取反    10000000000000000000000000000001
b = -1
打印结果为 -1

四、赋值操作符 =

赋值操作符可以连续使用

int a = 10;
int x = 0;
int y = 20;
a = x = y+1

五、复合操作符

+=、-=、*=、/=、%=、>>=、<<=、&=、|=、^=

六、单目操作符

!(逻辑反操作)

真变假,假变真,假变真有固定值0变成1

int main()
{
	int a = 0;
	if(!a)                一般情况下表达为a为真则打印hhh
		printf("hhh");
	if(!a)                一般情况下表达为a为假则打印lll
		printf("lll");
	return 0;
}
if(真)括号里是真就会执行,if(!真)括号里不是真的就会执行

&(取地址)

int main()
{
	int a =10;
	int* p = &a;
	&p = 20;
	return 0;
}

sizeof

1.计算变量所占空间大小

int main()
{
	int a = 10;
	char c = 'c';
	char* p = &c;
	int arr[10] = {0};
	printf("%d\n",sizeof(a));        int    4个字节
	printf("%d\n",sizeof(int));        int    4个字节
	printf("%d\n",sizeof(c));        char 1个字节
	printf("%d\n",sizeof(char));    char    1个字节
	printf("%d\n",sizeof(p));        char*8个字节
	printf("%d\n",sizeof(char*));    char*8个字节
	printf("%d\n",sizeof(arr));        int[10]40个字节
	printf("%d\n",sizeof(int [10])    int[10]40个字节
	return 0;
}

2.sizeof内的表达式不会直接发生运算,只会做好预处理的准备工作

int main()
{
	short s = 0;
	int a = 10;
	int sz = sizeof(s = a + 5);
	printf("%d\n", sz);
	printf("%d\n", s);
	return 0;
}
打印结果sz是2,s是0

3.sizeof内部的表达式不进行运算

int main()
{
	short s = 0;
	int a = 0;
	int sz = sizeof( s = a + 5);	s占两个字节
	printf("%d\n",sz);		sizeof内部的表达式不进行运算
	printf("%d\n",s);
	return 0;
}
打印结果为 0		2

前置/后置++/–

前置为先算再用
后置为先用再算

int main()
{
	int a = 10;
	printf("%d\n",++a);    前置++,先++再使用
	11
	printf("%d\n",a++);    后置++,先使用再++
	11
	return 0;
}

*(间接访问操作符)

int a = 5;
int* p = &a;
printf("%d",*p);
打印结果为5

(类型)强制类型转换

可能造成精度丢失(谨慎使用)
int main()
{
	int a = (int)3.14;
	printf("%d",a);
	return 0;
}
强行转换成int,打印结果为3

七、关系操作符

>、>=、<、<=、!=、==

八、逻辑操作符

比较的是数本身,不为 0 就是真

&&

两个数都为真则为1

int main()
{
	int a = 5;
	int b =3;
	int c = a && b;        a && b 两个都为真则为1
	printf("%d",c);
	return 0;
}
打印结果为 1

||

有一个为真就为1

int main()
{
	int a = 0;
	int b = 3;
	int c = a || b;    a || b其中一个为真就为真1
	printf("%d",c);
	return 0;
}
打印结果为1

特性

1.对于&&,表达式中最左边的式子为假,后面的将不会进行计算

int main()
{
	int i = 0,a = 0, b = 2, c = 3,d = 4;
	i = a++ && ++b && d++;
	printf("a = %d\nb= %d\nc = %d\nd = %d\n",a,b,c,d);
	return 0;
}
打印结果:a=1,b=2,c=3,d=4

2.对于||,表达式中最左边的式子为真,后面的将不会进行计算

int main()
{
	int i = 0,a = 0, b = 2, c = 3,d = 4;
	i = a++ || ++b || d++;
	printf("a = %d\nb= %d\nc = %d\nd = %d\n",a,b,c,d);
	return 0;
}
打印结果:a=2,b=2,c=3,d=4

九、条件操作符

exp1?exp2:exp3

1为真,执行2的结果 1为假,执行3的结果

练习
if(a > 5)
	b = 3;
else
	b = -3;
转换成表达式
b = (a>5?3:-3)

练习
if(a>b)
	max = a;
else
	max = b
转换成表达式
max = (a>b?a:b);

十、逗号表达式

从左向右依次执行,整个表达式的结果是最后一个表达式的结果

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)
只看d>0是否为真
a = get_val();
count_val(a)
while(a>0)
{
	业务处理
	a = get_val();
	count_val(a);
}
用逗号表达式改写
while(a = get_val,count_val(a),a>0)
{
	业务处理
} 

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

下标引用操作符

操作数:一个数组名+一个索引值
int arr[10]; 创建数组
arr[9] = 10; 实用下标索引值
[ ]的两个操作数是 arr 和 9

函数调用操作符

操作数:一个函数名,()内部的参数
操作符:()

int get_max(int x,int y)    创建函数
{
	return x>y?x:y;
}

int main()
{
	int a = 10;
	int b = 20;
	int max = get_max(a,b);
	printf("max = %d\n",max);
	return 0;
}

访问一个结构的成员

图纸:不占用空间
struct Stu(名称)
{
成员变量名
char name[20];
int age;
char id[20]
};        有分号    
通过图纸建房子:占用空间了
int main()
{
	int a = 10;
	使用struct Stu这个类型创建了一个学生对象s1,并初始化
	struct Stu s1 = {"张三",20,"20220101"};
	指针类型名称struct Stu
	struct Stu*ps = &s1;
	三种方式都等价
	结构体指针->成员名
	printf("%s\n",(*ps).name);    printf("%s\n",ps->name);
	printf("%d\n",(*ps).age);        printf("%d\n",ps->age);
	printf("%s\n",(*ps).id);        printf("%s\n",ps->id);

	printf("%s\n",s1.name);
	printf("%s\n",s1.age);
	printf("%s\n",s1.id);
	return 0;
}

十二、操作符的三个属性

在这里插入图片描述

1.操作符的优先级

2.操作符的结核性

3.是否控制求和顺序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值