【c语言】操作符详解

操作符的分类

操作符分为:

  • 算数操作符:+、-、*、/、%
  • 赋值操作符:=、+=、-=、/=、*=、%=、<<=、>>=、&=、|=、^=
  • 移位操作符:<<、>>
  • 位操作符:&、|、^、~
  • 逻辑操作符:&&、||
  • 关系操作符:>、<、==、!=、<=、>=
  • 单目操作符:&、+、-、~、*、++、–、siezeof(类型)、!
  • 条件操作符:? :
  • 下标引用操作符:[]
  • 函数调用操作符:()
  • 逗号操作符:,
  • 结构成员访问:.、->

算数操作符:

算数操作符不用多说了,就相当于数学里的加减乘除,但有一个需要注意的:%,取模(取余)操作符,它只能使用与整数或者整数的运算。

赋值操作符

赋值操作符里,需要注意的是类似于:+=、-=这类操作符,它实际上是:

a+=b;
//实际为
a=a+b;
**********
a-=b;
a=a-b;

移位操作符

位移操作符分为:左移右移
左移操作符(<<):将值所对应的二进制数,进行左移。
操作对象<<移的位数


int a=2;
a=a<<2;//这里a是操作对象,2是移的位数

这段代码是将a的值左移两位,也就是将0010左移两位变成1000。它输出的值则为:8
在这里插入图片描述

有的人看到这可能会疑惑,它左移后,右边的0是怎么来的呢?是这样的:
左移操作符,将值的二进制数左移相应的位数,移动多少位,右边就补上多少的0。再比如:

int a=12;
//0000 1100,这是12的二进制数
a=a<<3;

这里将12左移三位,那么得到的值是:96,而96对应的二进制数位: 0110 0000,与12的二进制数相比,1左移了三位,右边也补上了3个0。
在这里插入图片描述
右移操作符(>>):将值所对应的二进制位进行右移。
右移操作符和左移操作符是存在区别的,它分为:

  • 逻辑右移:将二进制的值右移,左边补0 。
  • 算术右移:将二进制的值右移,左边根据原二进制的值的符号位进行补充。

我想逻辑右移很好理解,与左移是一样的,但是算术右移是怎么一回事呢?
看下边:

int a=4;
//00000000000000000000000000000100 补码

a=a>>2;

将a的值右移两位,得到:1(00000000000000000000000000000001,补码),这里因为4的二进制位00000000000000000000000000000100的符号位是0(32个bit位的最前面的数字,1为负,0为正),所以左边补0 。
在这里插入图片描述
接下来我们再来个例子,观察一下。

int a=-4;
//10000000000000000000000000000100 原码
//11111111111111111111111111111100 补码
a=a>>2;

此时输出的结果为:-1(11111111111111111111111111111111,补码)。
在这里插入图片描述

原码、反码、补码

这里提一下原码、反码、补码。

原码:最高位作为符号位,其余位表示值。

比如:1的原码00000000000000000000000000000001-1的原码10000000000000000000000000000001。这里的最高位的数字就是最左边的数字,它表示符号位,0位正,1为负。因为1和-1都是整型,所以它的二进制数一共有八位,如果是char类型,它只占1字节,它的二进制数的位数则只有8位。

反码:如果是正数,则它的反码与原码相同,如果是负数,则它的反码是原码的符号位不变,其余位按位取反。

比如:1的原码是00000000000000000000000000000001,它的反码也是00000000000000000000000000000001-1的原码为10000000000000000000000000000001,则它的反码为:11111111111111111111111111111110

补码:如果是正数,则它的补码与原码相同,如果是负数,则它的补码是反码加一。

比如:-1的反码是11111111111111111111111111111110则它的补码是11111111111111111111111111111111。不管是左移运算还是右移运算,移动的二进制码都是补码。

位操作符

位操作符有三个:

  • 按位与(&):都为1则为1,否则为0
  • 按位或(|):有1则为1,否则为0
  • 按位异或(^):不同则为1,相同则为0
  • 按位取反(~):0变1,1变0(它也是单目运算符)

我们先来看个例子,按位与:

int a=2;//0010
int b=1;//0001
int c=a&b;//0000

此时,c为0。
在这里插入图片描述
再来看按位或的例子:

int a=2;//0010
int b=1;//0001
int c=a|b;//0011

此时c的值为3。
在这里插入图片描述

再来看按位异或的例子:

int a=12;//1100
int b=2;//0010
int c=a^b;//1110

此时c的值为:
在这里插入图片描述
再来看按位取反的例子:

int a=12;//00000000000000000000000000001110
a=~a;//取反后为11111111111111111111111111110011	

此时a的值为
在这里插入图片描述

看到这里,有的小伙伴可能会有点卡壳了,先不急,我一一道来。

int a=12;//00000000000000000000000000001110
a=~a;//取反后为11111111111111111111111111110011	

因为在计算机中,数值的二进制码都是以补码的形式存储的,所以对值进行位运算时都是对值的补码进行操作的。

这里a最开始等于12,因为他是正数,所以它的原反补都是一样的00000000000000000000000000001110,当对它进行取反运算后,我们得到的二进制码是11111111111111111111111111110011通过观察,我们会发现,这是一个负数的补码,由于负数的补码是原码取反加一,所以我们要把他转换位原码的形式10000000000000000000000000001101此时计算一下就能得出-13。

逻辑操作符

逻辑操作符分为:

  • 逻辑与(&&):都为1(真)则为1(真),否则为0(假)
  • 逻辑或(||):有1(真)则为1(真),否则为0(假)

这里就不用二进制的数进行举例了,我们上代码会更好理解:

#include<stdio.h>
int main()
{
	int a=1;
	int b=3;
	if(a<2&&b>2)//如果a小于2与b大于2同时成立,则为真,进入if语句,记住,时同时成立。
	{
		printf("yes");
	}
	return 0;
}
#include<stdio.h>
int main()
{
	int a=5;
	int b=3;
	if(a>3||b>3)只要a大于3和b大于3有一个成立的,就进入if语句
	{
		printf("yes");
	}
	return 0;
}

关系操作符

这部分我觉得不用过多的阐述,相信各位小伙伴们看一眼大概就知道这些符号是什么意思了。

  • 大于 >
  • 小于 <
  • 小于等于 <=
  • 大于等于 >=
  • 等于==
  • 不等于 !=

单目操作符

单目操作符:只操作一个对象的操作符
&、+、-、~、*、++、–、siezeof(类型)、!

  • 取地址符(&)
  • 正号(+)
  • 负号(-)
  • 按位取反(~)
  • 间接引用操作符(*),指针里会提到
  • 自增(++)
  • 自减(–)
  • 计算操作数的大小(sizeof),或者说计算操作数所占的字节大小。
  • 逻辑取反操作符(!)

取地址操作符我想小伙伴们应该不陌生吧,在使用scanf函数的时候是不是经常漏掉?
正负号操作符、按位取反操作符我想也不需要我赘述了,但是这里需要注意一下,按位取反(~)逻辑取反(!),前者是在二进制数中,0变1,1变0的,后者是逻辑取反,这里稍微解释下逻辑取反:

#include<stdio.h>
int main()
{
	int a=1;
	while(a)
	{
		printf("yes");
	}
	return 0;
}
*******************
#include<stdio.h>
int main()
{
	int a=1;
	while(!a)
	{
		printf("yes");
	}
	return 0;
}

在第一段代码中,当a为真(true)时,进入循环,输出yes,并且在循环中没有代码可以改变a的值,导致a永远为真,所以这是一个死循环,第二段代码中,加了一个!,意思为当a为假时,进入循环,但是a的值为1,所以不会进入循环。

siezeof操作符,用于获取特定类型或对象所占用的内存空间大小的运算符

#include<stdio.h>
int main()
{
    int a=10;
    printf("%zd",sizeof(a));
	return 0;
}

这里计算得出:
在这里插入图片描述
sizeof计算的是该操作对象的类型所占的内存大小,与操作对象的值无关。
再来个例子:

#include<stdio.h>
int main()
{
	int a[10]={1,2,3,4,5,6,7,8,9,10};
	printf("%zd",sizeof(a));
	return 0;
}

这里计算出来的结果为:
在这里插入图片描述
因为数组可以理解为同一类型变量的集合,所在该代码中共有10个int类型的变量,一个int类型的变量占的内存大小为4字节,10个就为40字节。

条件操作符

条件操作符也可以叫“三目操作符”。
直接上例子来讲解:

#include<stdio.h>
int main()
{
	int a=2;
	int b=1;
	printf("%d",a>b?1:0;);
	return 0;
}

这段代码的意思为:如果a>b为真,则输出1否则输出0。

下标引用操作符、函数调用操作符

下标引用操作符:当我们创建完一个数组后,想要访问数组中某一位置的值,就需要用到下标引用操作符。

int a[10]={1,2,3,4,5,6,7,8,9,10};
//这里我们要输出下标位3的元素的值。在这之前我得先访问该位置
printf("%d",a[3]);//通过下标引用符,访问下标为3的元素的值,并输出

函数调用操作符:在调用涵数时使用。

#include<stdio.h>

int add(int a)
{
	a++;
	return a;
}

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

逗号操作符

逗号表达式:exp1, exp2, exp3, …expN
逗号表达式,就是⽤逗号隔开的多个表达式。
逗号表达式,从左向右依次执⾏。整个表达式的结果是最后⼀个表达式的结果


int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
c是多少?,这里c的值就为b=a+1的值:13

a = get_val();
count_val(a);
while (a > 0)
{
 //业务处理
 //...
 a = get_val();
 count_val(a);
}
如果使⽤逗号表达式,改写:
while (a = get_val(), count_val(a), a>0)
{
 //业务处理
}

结构成员访问

c语言提供了char、int、double、float等内置类型,但是只有这些内置类型变量还是不够的,假设我想描述学⽣,描述⼀本书,这时单⼀的内置类型是不⾏的。

描述⼀个学⽣需要名字、年龄、学号、⾝⾼、体重等;

描述⼀本书需要作者、出版社、定价等。C语⾔为了解决这个问题,增加了结构体这种⾃定义的数据类型,让程序员可以⾃⼰创造适合的类型。

结构体的声明:

struct 结构体标签
{
	成员变量1
	成员变量2
	.
	.
	.
}结构体变量;

描述一个学生:

struct student
{
	char name[20];
	int age;
	int height;
	double weight;
};
结构体变量的定义和初始化

struct Point
{
	int  x;
	int y;
}p1;//声明类型的同时,定义变量p1
struct Point p2;定义结构体变量p2
struct Point p3={10,20};//结构体变量初始化
**********************************
struct Stu
{
	char name[20];
	int age;
};
struct Stu s1={"lisi",10};//初始化
struct Stu s2={.age=10,.name="lisi"};//指定顺序初始化
***********************************
struct Point
{
	int  x;
	int y;
};
struct Node
{
	int data;
	struct Point p;
	struct Node*next;
}n1={1,{10,20},NULL};//结构体嵌套初始化
struct Node n2={2,{10,20},NULL};//结构体嵌套初始化
结构体成员访问

结构体成员的直接访问:我们通过(.)点操作符进行访问。

#include<stdio.h>
struct Point
{
	int  x;
	int y;
}n={10,20};
int main()
{
printf("%d %d",n.x,n.y);//输出x,y的值
return 0;
}

结构体成员的间接访问:有时候我们得到的不是⼀个结构体变量,⽽是得到了⼀个指向结构体的指针。如下所示。

#include<stdio.h>
struct Point
{
	int  x;
	int y;
};
int main()
{
struct Point p={10,20};
struct Point *ptr=&p; 
ptr->x=1;//修改x的值
ptr->y=2;//修改y的值
printf("%d %d",ptr->x,ptr->y);//输出x,y的值
return 0;
}
  • 42
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值