【C语言】操作符详解

这个相信各位小可爱们已经很熟悉了,这里只是将一些注意事项写了出来,内容会比较简洁,有什么问题可以评论区里讨论哦~

目录

算术操作符

移位操作符

位操作符

 //交换两个数

赋值操作符

单目操作符

//sizeof

         // ~ 按位取反

关系操作符

逻辑操作符

条件操作符

逗号表达式

下标应用,函数调用,结构成员

struct 结构体——自定义类型(聚合类型)


 

算术操作符

+ - * / %

对于除法操作符 / 来说,两边的操作符都是整数时,执行的是整数除法,如果想计算算出小数,那除号的两端至少有一个数是浮点数。取模操作符两边的数只能是整数模运算时,当运算对象中有负整数时,运算结果的符号与被除数相同

注意:-3/2=-1,3/-2=-1,-3%2=-1,3%-2=1

 

移位操作符

<<左移操作符,>>右移操作符

采用二进制,操作数只能是整数。

原码--按位取反-->反码--加一-->补码

取反或加一时符号位不变

 正数的原反补码均相同,负数在内存中存储的是二进制的补码,但是用的打印的是这个数的原码。左右位移只在补码层面上执行。第一位是符号位,0为正,1为负。

 对左移来说,不论是有符号数还是无符号数,都补0;而对右移来说,分为算数位移(右边丢弃,左边补原来的符号位)和逻辑位移(右边丢弃,左边补零)。

这里有一个计算的小技巧:左移k位,相当于乘以2^k,右移k位,相当于整除2^k 

unsigned——无符号,最高位不是符号位,但是默认为正数 。即使在里面放了一个负数,计算机也会将这个数的最高位当作有效数值而不是符号。

73684e8a43c9428fb8f6937546035464.png

 这时候打印出来的值就异常大,见左图

 

 

 

 

位操作符

&按位与,|按位或,^按位异或   

这里主要讲解一下^按位异或:

异或操作符:a ^ a = 0,0 ^ a = a ,支持交换律

缺点:可读性差,效率不如使用临时变量的方法,且只能针对整数的交换

 //交换两个数

正常情况下我们会创建一个临时变量,非常简单,这里就不赘述了。

还有一种有意思的小方法,主要考察数学计算能力,见下:

int main()
{
	int a = 3;
	int b = 5;
	a = a + b;
	b = a - b;//相当于 ( a + b ) - b = a 
	a = a - b;//相当于 ( a + b ) - a = b
	printf("a=%d,b=%d", a, b);
	return 0;
}

但是这种方法当a,b很大时,即使a,b在正常范围内,a+b也可能会溢出。 

最后我们来看看怎么用位操作符来实现这个程序的。这里要熟练应用上面提到的交换律和a ^ a = 0 ,0 ^ a = a 。这种方法不会溢出,但是效率不如使用临时变量的方法。(异或虽好,可不要贪杯哦~)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	int a = 3;
	int b = 5;
	a = a ^ b;
	b = a ^ b;//相当于 ( a ^ b ) ^ b = a ^ ( b ^ b ) = a ^ 0 = a
	a = a ^ b;//相当于 ( a ^ b ) ^ a = ( a ^ a ) ^ b = 0 ^ b = b 
	printf("a=%d,b=%d", a, b);
	return 0;
}

5fb52ac6f32442f7b7eb47fed339fc33.png

 

赋值操作符

=  +=  -=  *=  /=  %=  ……

可连续赋值:从右向左,如a = x = y + 1,但可读性不强

 

单目操作符

+  -  ! &  ~  --  ++  *  sizeof  ()

同理,这里只介绍一些注意事项及拓展:

布尔类型:C99中引用的,是用来表示真假的类型。头文件#include<stdbooll.h>

只有两种赋值,返回true和false,实际上就相当于返回1和0。

下面来举两个小栗子: 

int main()
{
	_Bool flag = true;//false
	if (flag)
	{
		prinf("hehe\n");
	}
	return 0;
}


//判断闰年
_Bool is_leap_year(int y)
{
	if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//sizeof

sizeof 后面的()有时候可以省略,说明sizeof不是函数 ;

sizeof内部的表达式是不计算的!!

 cf596327708c43e697b77596093ada75.png

当一个整型数据非得要放在短整型数据中时,会发生 截断 。,简单来说就是强龙难压地头蛇哈哈 

sizeof与数组:*数组传参,形参可以写成数组,也可以写成指针。

#define _CRT_SECURE_NO_WARNINGS
#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);//传过去的是首元素的地址
    return 0;
}


在x64和x86环境下结果不同——x64:40 40 4 4;x86:40 40 8 8。

在x64环境下,会出现下面警告,此时将%d改为%zd即可 618ad97ced9c4fc48fae409465f3f34e.png

// ~ 按位取反

~ 是所有位(包括符号位)按位取反

如果我们想 具体改变一个数二进制中的某一位,可通过 & | ^  ~ 的综合使用来实现。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	//将a的二进制中的第五位改成1
	int a = 9;//000000000000000000001001
	                       //目的:^将这一位改成1
  //只需按位或| 000000000000000000010000  *( 这个可通过 1 << 4 得到 )
  //变成目标结果000000000000000000011001  = 25 
  //综上,可总结代码如下:

	a |= (1 << 4);
	printf("%d\n", a);

	//再将a的二进制中的第五位改回来,变成0
	          //000000000000000000011001
	                       //目的:^将这一位改成0
  //只需按位与& 111111111111111111101111 ( 这个可通过 * 式按位取反 ~ 得到 )
  //变成目标结果000000000000000000001001 = 9
  //综上,可总结代码如下:
	a &= (~(1 << 4));
	printf("%d\n", a);
	return 0;
}

ef9b9e7ee96346a4a006c3e112043cf9.png

 

关系操作符

>  >=  <  <=  ==  !=

这里只有一个注意事项:= 和 == 要区分开哦!

逻辑操作符

&&(逻辑与)||(逻辑或)  

注意:&&操作符最左边为假时,后面无需计算,||操作符最左边为真时,后面也无需计算。

下面举一个例子(某大厂面试题哦):

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

根据上面的小Tips,答案是1,2,3,4。你算对了吗? 

条件操作符

exp 1 ? exp 2 : exp 3

exp 1为判断条件,真则执行exp 2,假则执行exp 3。

逗号表达式

exp 1 ,exp 2 ,exp 3 ,…… exp N

从左向右依次执行,整个表达式结果为exp N的值。

来小试一下吧~

int main()
{
	int a = 1;
	int b = 2;
	int c = (a > b, a = b + 10, a, b = a + 1);
	printf("%d\n", c);
	return 0;
}

 算完了吗?答案是13,相信这一定难不倒你吧~

逗号表达式还可以用来简化代码,但是前提是你能看懂哈,可不要随便用哦

int main()
{
	int a = 0;
	a = test1();
	test2(a);
	while (a > 0)
	{
		a = test1();
		test2(a);
	}
	return 0;
}
//上述代码可用逗号表达式简化为:
int main()
{
	int a = 0;
	while (a = test1(), test2(a), a > 0);
	{
		;
	}
}

下标应用,函数调用,结构成员

[ ]——下标引用操作符:操作数为数组名和下标数,两者缺一不可。如 arr [ 4 ] 。

( )——函数调用操作符:操作数为函数名和参数,至少有函数名。如 test ( n )。

struct 结构体——自定义类型(聚合类型)

生活中有些对象要被描述的话,不能简单地使用单个内置类型。这时候便需要结构体出马了。

结构体变量.成员名      结构体指针->成员名 

struct Book  //注意这里不需要封号
{
	char name[20];
	char author[30];
	int price;
};  //注意这里封号不能丢

void print(struct Book* p)
{
	//结构体指针->成员名
	printf("《%s》%s %d\n", (*p).name, (*p).author, (*p).price);
	printf("《%s》%s %d\n", p->name, p->author, p->price);
}

int main()
{
	struct Book b1 = { "C语言","张三",66 };
	struct Book b2 = { "C++","李四",88 };
	//结构体变量.成员名
	printf("《%s》%s %d\n", b1.name, b1.author, b1.price);
	printf("《%s》%s %d\n", b2.name, b2.author, b2.price);
	return 0;
}

9f8346dd725c4bdbaf5d2625cb1babbc.png

 

以上就是操作符的全部讲解了,希望对大家有所帮助,我们一起进步!! 

 

 

 

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值