操作符详解

操作符类别

  1. 目录

    算术操作符

    移位操作符

    位操作符

    赋值操作符

    单目操作符

    关系操作符

    逻辑操作符

    条件操作符

    逗号操作符

    下标引用,函数调用和结构成员


1.算术操作符

 +      -      *      /     %(模)五个

1.模是用来求余数的

2.对于除法而言,如果是整型除以整型的话,除出来的结果也是整型,其为实际结果去掉余数

如果想要得到实际结果的话需要有三部走  一.用一个浮点型变量来存储结果 ;二.如果是整型除以整型的话,要将其中一个整型用小数形式来表现,如 1/2 要变为 1.0/2 或者是 1/2.0 ; 三 . 如果是变量相除的话,这个变量要是浮点型的。

3.对于取模而言 -- % ,它的左操作数和右操作数都必须是整型 ,不能是浮点型 如

1.2%2 这种写法就是错的,必须是1%2

算术操作符的复合情况:

1+3+2/3*4%5

这种情况的读写顺序如下:

1.分部分:将加减法,和乘除模分成两部分算

2.按顺序:加减法和乘除模都按照从左到右的顺序来算

如上面那个

先分两部分 : 1 +3+() 

然后括号内按顺序:

1+3 = 4

4 +()

括号内按照从左到右的顺序求结果: 2/3 = 0(整型相除时向下取整)

0*4 = 0   --  0 %5 = 0;


2.移位操作符(整型)

 >>(右移操作符)  <<(左移操作符)

int main()
{
    int a = 13:
    int b = a >> 1; 
// >> 右移操作符 -- 移动的是二进制位
// 对于移位操作符,不要移动负数位,这个是标准未定义的!!! 如 a >> -1 这种写法是错误的
//移位操作符只能作用于整数,千万不要作用于浮点数上去了!!!
    return 0;
}

操作符详解_第1张图片

 右移操作符--二进制整体向右移一位,左移则是整体向左移动一位,其中我们先来讲讲右移

我们发现右移之后,二进制位的最右边要舍弃一位,左最边就会空一位,那这一位要填什么呢?

这一位填什么由右移的具体移动方式来确定,而这具体移动方式分为:

1.算术右移

算术右移要考虑符号位,此时在算术右移后我们要在左边空的哪一位上补上没右移时的的符号位

(右边丢弃,左边补原符号位)-- 一般电脑采用的都是算术右移

2.逻辑右移

逻辑右移的话就是右边直接丢弃。左边补0

右移格式:

要被右移的数  >> (右移操作符) 被移的位数   --  如 a >> 2 ,并且右移一位有除2的效果,这就和十进制中右移一位有除10的效果一样,如10右移一位就变成了1(10/10)


关于整数的存储:

1.整数的二进制表示有原码,反码,补码

2.存储到内存中的是补码

3.正数的源码,反码和补码都一样

4.负数的源码反码补码的关系是 反码 = 源码符号位不变然后按位取反 , 补码 = 反码 +1(存储空间一定,超出了存储空间的话就自动去掉超出的部分)

5.不要忘了符号位,1表示负数 , 0表示正数


左移操作符:

只有一种情况,就是左边丢弃一位,右边补0


3.位操作符(整型)

分别有

&  : 按位与 -- 按照二进制位与

int main ()
{
    int a = 3; 
// 011(简单表示,如果完整表示的话则有多少位就要写多少个二进制数,如32位就写32个二进制数,即32个比特,没存东西的时候,所有二进制位数都为0,存了数就按二进制的方式表示这个数的大小)
    int b = 5; 
// 101
    int c = a & b;
/*按位于计算 : 对应位置都为1则为1,否则为0
c = a & b ;
按位与左边的二进制放上面,右边的放下面
即011
  101
此时c中存储的二进制数由按位与计算得来,从左边第一位开始,都为1则c的二进制的第一位为1,否则为0,依次进行下去得到c中存的二进制数*\
    return 0;
}

|  : 按位或 -- 按二进制位或 --  a | b -- 上下只要有有一个为1,则c对应的位为1,都为0时,则为0

^ : 按位异或 -- 按二进制位异或 --  a ^ b -- 上下对应相同为0,相异为1 -- 得到c对应位的二进制数

注意: 它们的操作数必须是整数!!

如何通过位操作符在不建立第三个变量的情况下实现两个整型的数值交换

int a = 3;
int b = 5;
a = a^b;
b = b^a;
a = a^b;
return 0;
这样就能实现无第三个变量的整型数值交换了
实现思想如下:


另一种方法:
a = a + b;
b = a - b;
a = a - b;
缺陷:当a和b都是一个接近存储极限,但依然没有溢出机器位数的值的时候
a和b一相加就会导致数据的溢出,这样就会使得我们想要的数据丢失,进而得到一个错误的结果
这样也能够实现a和b的交换

为了解决这个溢出的问题,我们可以使用位操作符法来实现两数的交换
位操作符法中我们使用的主要是异或的方法
a = a^b;
b = b^a;
a = a^b;

原理如下
在异或操作中存在以下这样一个规律
int c = a ^ b ;
若 c ^ a 则 = b
若 C ^ b 则 = a

(2进制中的模2除2和十进制中你的模2除2的效果和处理方式是一样的,且整型的二进制模2除2和10进制中的模2除2结果完全一致)一个二进制数按位与1的话,若结果0,则对应位必为0,否则必为1

假设我们要知道一个4位的二进制数最后一位的值,我们就可以用0001来按位与这个数

按位与时,0遇到仍和一个数,都输出0,这样就排除掉了除最后一位外其他所有位的影响了。

然后最后一位按位与1,若输出结果为0,则二进制数a的结果为0,否则为1

判断了最后一位后,如果我们想知道它上一位的结果的话,我们只需要用右移操作符右移一位,然后再用0001判断即可

并且判断的结果就是我们想要输出的结果


4.赋值操作符

“   =  ”  这个是赋值操作符,'  ==  '这个是等于的判断操作符

变量在创建的时候给它一个值叫做初始化,初始化后再给一个值叫叫作赋值

赋值还支持连续赋值,而连续赋值的读写顺序:

以 a = b = x +y ;   为例  先读右边,再读左边,则拆分开来的逻辑顺序为

b = x + y;

a = b; 


5.复合赋值符 -- 复合赋值符就是我们给定的参数和它本身之间的操作

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

a = a+1  ==>   a += 1  其它的同理

要被操作的变量  复合赋值符  用来改变变量的参数


6.单目操作符 -- 只有一个操作数

a + b ,“ + ”号左边和右边共有两个操作数,所以+号是双目操作符

单目操作符就是只有一个操作数

!  逻辑反操作 -- 就是把真变成假,假变成真,如 !10,10为真,把10变成假后再输出,而假为0,所以输出结果为0,int a = 10 , !a也一样

另外,我们规定0在逻辑反操作后得到的结果是1,1为真,但真不一定是1,任何非0的数都是真

//逻辑反操作的应用
 if (!a)
{
    printf("%d",hehe);
}

if(a) -- 这种就是如果a为真就执行if结构
if 结构必须得在if的(括号中)为真时才执行,而此时if的括号中若要为真的话,a要为假
翻译过来就是当a为假时执行if语句

-     负值(这里是作为负值标识符的时候的减号,而不是做减法时的减号,下面的加号同理)

+    正值

& :取地址

sizeof:操作数的类型长度(以字节为单位)-- 计算的是变量所占内存空间的大小,单位是字节

数组也是有类型的!数组去掉数组名后就是它的类型 --- 如

int arr [ 10 ] = {0}  这个数组的类型就是  int [ 10 ]

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

--:前置,后置--

++:前置,后置++

*:间接访问操作符(解引用操作符,这里不是作乘法时的那个双目操作符)

(类型):强制类型转换

short,两个字节(平时写代码的时候我们可以用这个简写代表short int)是短整型 -- 它的全程是shot int

长整型是long ,字节是四 , 全程是long int ,除了一个长整型外我们还有一个长整型plus版,即

long long -- 全名是 long long int   字节是四

double类型 -- 8字节,float -- 4字节

关于sizeof的一个比较坑的题目

int main ()
{
    short = 0;
    int a = 10;
    printf("%d\n" , sizeof( s = a + s ));
    printf("%d\n" , s);
}
sizeof计算的是类型所占空间的大小!!!而不是数字的大小
不如说你一个短整型a存储15这个数的二进制位,sizeof(a) = 2
因为我们计算的是类型所占空间的大小,单位是字节!
另外!!!
sizeof的括号中你的表达式并不会被执行,那个表达式在sizeof看来只是一些无意义的符号
sizeof真正看重的是它括号里的主体的类型是什么
然后sizeof通过获取这个类型得到这个类型所占内存空间的大小

(数组作为参数的时候传过去的是指针,由传过去的指针--编码1,和下标(通过我们给定的元素个数得出)编码2我们可以访问整个数组, void tsrt( int arr[10]),这里的arr[10]不代表整个数组,它只是由两个参数合成的一个复合参数,arr:,指针变量,存放的是首元素地址,10:元素个数,所以sizeof(arr)算的是首指针变量类型所占的内存空间的大小,我们可以通过这个复合的变量访问数组中你的每一个地址


7.关系操作符 -- 用来比较大小的

>=

<

<= 

!= -- 判断不相等

==  -- 判断等于


8.逻辑操作符

&& : 逻辑与  a && b  ,a和b都为真的时候才为真

|| : 逻辑或   a || b , a和b中有一个为真时为真

另外 若有 c = a && b 的话,则有 a和b都为真的时候 ,c = 1 ,否则c = 0,按位或同理

(a++ 单独放的时候和 ++a没有区别 ,但是 a++ 和别的语句一起用的时候顺序是:先使用a,然后再将a+1,++a则是先a+1然后再使用a)

操作符详解_第2张图片

逻辑操作符的运算逻辑:

操作符详解_第3张图片

以上面这一个图为例

对i进行分析

首先读进a++,即先使用a然后在对a+1

此时我们先使用a进入逻辑判断,已知a = 0,且i中的逻辑判断为 与 判断,可知i中的逻辑为假,计算机一旦判断到逻辑为假/为真则直接输出0/1,语句结束。

在哪里判断结束,哪里为判断结束点,判断结束点后的操作符等都不执行(处于同一语句下)!

逻辑判断如果没有判断出真或假,判断继续,一旦判断出真或假,则直接输出1/0,判断直接结束。


9.条件操作符 -- 三目操作符

exp1 ? exp2 : exp3 -- exp是表达式的意思

如果表达式1为真,则表达式2要计算,否则表达式3要计算

例子如下:

b = ( a > 5 ? 3 : 4 )

a>5是否为真,若为真b=3否则b=4,写等号的时候不要忘了加括号




一些杂项:

1.关于 %m.n + 字符类型的读写规定

其中m是我们规定的输出结果最多能够占用的字符位数,并且这个字符位数用正数来表示时,则我们输出的字符为右对齐,反之为左对齐,.n表示我们的输出结果想要保留到小数点后几位


2.关于printf( "%%d" ) 的区分情况

在c语言中,%常用来最为类型声明的标识符,如%d,如果没有这个%在d前面作为标识符的话,printf函数只会认为d是字符d而不是类型声明里的d。

因此,当我们想要输出字符%,而不是让%作为类型声标识符的时候,我们需要在%前再加一个%来告诉计算机我们要输出的是字符%

既有printf ("%%")  -- 输出结果为一个% ,而失去了标识符的d也就不再是类型声明了,现在它只是一个普通的字符d,所以%%d的输出结果为%d


3.关于强制类型转换

1个字节(byte)有八个比特(bit),每个比特都代表一个0/1

c语言中强制类型转换,转换的是不同类型之间所占的内存空间的大小,如

浮点型 double 1.1 所占的内存空间是8个字节,64个比特

强制类型转换 -- (int)1.1 -- 此时将1.1存储的内存空间大小强制转换为整型的内存空间大小,即4个字节,32个bit,此时缺少的32个bit直接被去掉了。

可以看这个链接

强制类型转换的处理对象是存储在内存空间中的数据的补码

而对整数来说  原 = 反 = 补,对正数进行强制类型转换后若符号位不变则不用进行任何操作,若符号位改变为1的话,则我们此时得到的是一个负数的原码,要想得到这个负数的值的话我们还需要求真正存储在内存空间中的补码才能知道这个负数真正的值。


4.关于 if(x==a) 和 if(x = a) 的区别以及  x++,++x的运算优先性和在if while等情况下的使用分析

if结构的判断逻辑是只要if括号中的内容为真,那么就执行if下的语句则有

第一个:x == a 如果x 等于a为真,那么就执行if,否则不执行,

第二个x = a 意思是先将a赋值给x,然后看x是否为真,若为真就行if,否则不执行(非0为假,否则为真)

讲到这就必须得说在同一语句中,变量的赋值优先执行,然后再执行判断等非变量赋值操作

其中变量的赋值除了普通的x = a + 2;这种还有两个特殊情况,分别是x++,和++x型 -- 同理

x++ ,先调用x然后再将x+1

++x,先将x+1然后再调用x

if(x++) -- 先判断x是否为真,然后将x+1(两个操作互不影响)

if(++x),先将x+1,然后再判断x是否为真

另外if中的判断是从左到右读的!!


操作符详解_第4张图片

年份计算

闰年判断

操作符详解_第5张图片

你可能感兴趣的:(c语言学习,c语言)