【C语言】运算符

算术运算符

+  -  *  /  %	++	--

1.除了%操作符之外,其他的几个操作符可以作用于整数和浮点数
2.%操作符的两个操作数必须为整数。返回的是整除之后的余数。
3.对于/操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。

关系运算符

>	<	>=	<=	!=	==	

C语言的基本数据类型有char、int、double,我们暂时认为只有char和int适用于上述关系运算符,double和字符串(字符数组)的关系运算以后再讨论。

注:“=”是赋值,“==”才是判断两个数是否相等,不能混用


逻辑运算符

&&	逻辑与
||	逻辑或
!	逻辑非
  1. 区别 逻辑与&&和 按位与&
    1&&2 -----> 1
    1&2 -------> 0
    1.&&具有短路功能,而&不具有短路功能。
    2.当&运算符两侧的表达式的结果均为真时,整个运算结果才为真。
    当&&操作符第一个表达式为 false时,结果为 false,并且不再计算第二个表达式。
  2. 区别 逻辑或|| 和 按位或 |
    1 || 2 -----> 1
    1 | 2 ------> 3
    || 和 | 都是表示“或”,区别是||只要满足第一个条件,后面的条件就不再判断,而|要对所有的条件进行判断。

&& 和 || 的代码

#include<stdio.h>
int main(){
	 int i = 0,a = 0, b = 2,c = 3, d = 4;
	 i = a++ && ++b && d++;
	 printf("a = %d\n b = %d\n c = %d\n d = %d\n",a,b,c,d);

	return 0;
}

结果:1 2 3 4
#include<stdio.h>
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;
}

结果:1 3 3 4
#include<stdio.h>
int main(){
	 int i = 0,a = 1, 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;
}

结果:2 2 3 5
#include<stdio.h>
int main(){
	 int i = 0,a = 1, 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;
}

结果:2 2 3 4

赋值运算符

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

赋值运算符支持的是C语言的基本数据类型,包括char、int和double,字符串(字符数组)不能使用赋值运算符。


逗号运算符

expl,exp2,exp3,…expn
逗号表达式,就是用逗号隔开的多个表达式。逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。

#include <stdio.h>
int main(){	
	int a = (3, 4, 5);
	printf("a=%d\n", a);	//a = 5

	return 0;
}

条件运算符

exp1 ? exp2 : exp3

2>1 ? 10 : 20

因为2>1成立,因此它的值就是表达式2的值,也就是10。


sizeof运算符

sizeof是C语言的关键字,它用来计算变量(或数据类型)在当前系统中占用内存的字节数
sizeof不是函数,产生这样的疑问是因为sizeof的书写确实有点像函数,sizeof有两种写法

①用于数据类型
sizeof(数据类型);
数据类型必须用括号括住。

 printf("字符型变量占用的内存是=%d\n",sizeof(char));   
 // 输出:字符型变量占用的内存是=1
  printf("整型变量占用的内存是=%d\n",sizeof(int));   
  // 输出:整型变量占用的内存是=4

②用于变量
变量名可以不用括号括住,带括号的用法更普遍,大多数程序员采用这种形式。

sizeof(变量名);
sizeof 变量名;

sizeof的应用

1.求数组的大小

#include <stdio.h>
int main()
{
    int arr[10]= { 0 };
	printf ("%d\n" , sizeof(arr));			//40,单位是字节
	printf ("%d\n", sizeof(int[10]));		//40, int[10]是arr数组的类型
    
    return 0;
}

2.sizeof计算指针

#include <stdio.h>

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;
}

用sizeof求数组大小时要注意,当数组被当作参数传递过去时,传过去的是数组的首元素的地址,因为是地址,所以用指针来接收,所以函数里面用sizeof求的都是指针的大小,不是数组,32位平台下都是4字节,64位平台下都是8字节

3.特殊例子:

#include <stdio.h>
int main()
{
    short s =5;
    int a = 10;
    printf ( "%d \n", sizeof(s = a + 2));		//结果为:2
    printf ( "%d \n", s);			//结果为:5
    
	return 0;
}

解释:因为sizeof括号中的表达式是不参与运算的! 源文件在变成可执行文件过程中,经过预处理,编译,汇编,链接,sizeof在编译中就判断了s的大小,给出值为2,并且表达式不参与运算,而printf函数是在运行的时候再执行的,所以直接打印出2,和下面s变量的值5

strlen与sizeof的区别

strlen -函数:求字符串长度的,找’\0’之前出现的字符个数
sizeof -操作符:算变量/类型所占内存大小,单位是字节

sizeof的返回类型

#include <stdio.h>
int i; 		//i是全局变量,不初始化,默认是0
int main ()
{
    i--;		//-1
    if (i > sizeof(i)) 
    {
    	printf ( "> \n" );
    }
    else
    {
    	printf ("<\n");
    }
    return 0;
}

这个例子的输出结果是>,sizeof这个操作符,算出的结果的类型是unsigned int,因为大小是没有负数的,当进行 i > sizeof(i) 比较时,会把有符号的 i 算术转换为无符号,因为-1在内存中全1存储,变为无符号后原码补码一样,将会是一个很大的数,肯定比4字节大,所以输出>


移位运算符

<< 左移位操作符
>> 右移位操作符
注:他们的操作数都必须是整数

右移操作符移位规则:

  • 算术右移:右边丢弃,左边补原符号位
  • 逻辑右移:右边丢弃,左边补0

左移操作符移位规则:

  • 算术左移和逻辑左移一样都是右边补0

算术左移和算术右移主要用来进行有符号数的倍增、减半;
逻辑左移和逻辑右移主要用来进行无符号数的倍增、减半;

#include<stdio.h>
int main(){
    int a = -1;
    //整数的二进制表示有:原码、反码、补码
    //存储到内存的是补码
    //10000000,00000000,00000000,00000001    原码
    //11111111,11111111,11111111,11111110    反码
    //11111111,11111111,11111111,11111111    补码
    int b = a>>1;
    printf("%d\n",b);		//b = -1
    					    //因此,计算机采用的是 算术右移

    return 0;
}

位运算符

& 按位与
| 按位或
^ 按位异或
注:他们的操作数都必须是整数

不能创建临时变量(第三个变量),实现两个数的交换。

但实际开发会选择创建第三个变量,执行的效率和开销
都大于以下两种方法
//法一
#include<stdio.h>
int main(){
	int a = 10;
	int b = 20;
	a = a^b;
	b = a^b;
	a = a^b;
	printf("a = %d  b = %d\n",a,b);

	return 0;
}
-----------------------------------------------
//法二
#include<stdio.h>
int main(){
	int a = 10;
	int b = 20;
	a = a+b;
	b = a-b;
	a = a-b;
	printf("a = %d  b = %d\n",a,b);

	return 0;
}
求一个整数存储在内存中的二进制中1的个数
#include <stdio.h>
int main()
{
    int num = 0;
    int count = 0;
    printf("请输入一个整数:");
    scanf("%d",&num);
    //方法一(当值为负数时不满足)
    // while (num)
    // {
    //     if (num % 2 == 1)
    //         count++;
    //     num = num / 2;
    // }

    //方法二
    // int i = 0;
    // for(i = 0; i < 32 ; i++){
    //     if(1 == ((num>>i) & 1))
    //         count++;
    // }

    //方法三
    while(num){
        count++;
        num = num&(num-1);
    }

    printf("二进制中1的个数 = %d\n", count);

    return 0;
}
比较两个数二进制中不同位的个数
#include <stdio.h>

int count_bit_one(int n){    
    int count = 0;
    while(n){
        n = n&(n-1);
        count++;
    }
    return count;
}

int get_diff_bit(int m,int n){
    int tmp = m^n;    //异或之后不同的位都变为二进制1
    int count = 0;
    return count_bit_one(tmp);    //统计二进制1的个数
}

int main(){
    int m = 0;
    int n = 0;
    printf("请输入两个整数:");
    scanf("%d%d", &m,&n);
    int count = get_diff_bit(m,n);
 
    printf("count = %d\n", count);

    return 0;
}

输入:1999 2299
结果:count = 7

下标引用、函数调用和结构体

下标引用[]
函数调用()
结构体 . 	->

单目运算符

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

!逻辑取反~ 按位取反 的区别:
! :代表逻辑取反,即:把非0的数值变为0,0变为1
~ :表示按位取反,即在数值的二进制表示方式上,将0变为1,将1变为0

~ 按位取反反码 的区别:
按位取反不考虑符号位,所有位都取相反
反码需要保留符号位,除符号位以外所有位取反

#include<stdio.h>
int main(){
    int a = 0;
    int b = 5;
    int c = 0;
    // ~ 按(二进制)位取反
    //00000000,00000000,00000000,00000000	原/反/补
    //11111111,11111111,11111111,11111111   补码
    //11111111,11111111,11111111,11111110   反码
    //10000000,00000000,00000000,00000001   原码
    printf("%d\n",~a);	    // -1
    printf("%d\n",!b);		// 0
    printf("%d\n",!c);		// 1

    return 0;
}

运算符的属性

  • 操作符的优先级
  • 操作符的结合性
  • 是否控制求值顺

表格优先级从上到下,依次递减

类别运算符结合性
后缀运算符[ ] ( ) . ->从左到右
单目运算符+ - ! ~ ++ - - & * (类型) sizeof从右到左
算术运算符* / %从左到右
算术运算符+ -从左到右
移位运算符<< >>从左到右
关系运算符> < >= <=从左到右
关系运算符== !=从左到右
位运算符&从左到右
位运算符^从左到右
位运算符|从左到右
逻辑运算符&&从左到右
逻辑运算符||从左到右
条件运算符? :从右到左
赋值运算符= += -= *= /= %= <<= >>= &= ^= |=从右到左
逗号运算符.从左到右

1. 同一优先级的运算符,运算次序由结合方向所决定。
2. 简单记就是:! > 算术运算符 > 关系运算符 > && > || > 赋值运算符
3.只有 单目运算符、赋值运算符、条件运算符的结合性是 从右到左

#include<stdio.h>
int main(){
	int a,b,c;
	a = 5;
	c = ++a;
	b = ++c,c++,++a,a++;
	b += a++ + c;
	printf("a = %d b = %d c = %d\n",a,b,c);
	//a = 9		b = 23		c = 8
	//赋值运算符高于逗号运算符
	return 0;

}

算术转换

如果某个操作数的类型较低,那么要先转换为另一个操作数的类型后再执行运算


隐式类型转换

C的整型算术运算总是至少以缺省整型类型的精度来进行的
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。

如何进行整体提升呢?
整形提升是按照变量的数据类型的符号位来提升的

//计算机中是以补码形式存放数据

#include<stdio.h>
int main(){
    char a = 3;
    //00000000 00000000 00000000 00000011   原码/反码/补码
    //00000011  a占1字节

    char b = 127;
    //00000000 00000000 00000000 01111111   原码/反码/补码
    //01111111  b占1字节

    //a和b如何相加
    //00000000 00000000 00000000 00000011
    //00000000 00000000 00000000 01111111
    //00000000 00000000 00000000 10000010

    char c = a+b;
    //10000010  c(最高位为1),则c为负值,符号位为1
    //11111111 11111111 11111111 10000010   补码
    //11111111 11111111 11111111 10000001   反码
    //10000000 00000000 00000000 01111110   原码---->  -126
    printf("%d\n",c);   c ---->  -126

    return 0;
}
#include<stdio.h>
int main(){
    char a = 0xb6;
    short b = 0xb600;
    int c = 0xb6000000;
    if(a == 0xb6){
        printf("a");
    }
    if(b == 0xb600){
        printf("b");
    }
    if(c == 0xb6000000){
        printf("c");
    }

    return 0;
}
//打印 c
#include<stdio.h>
int main(){
    char c = 1;
    printf("%u\n",sizeof(c));   //1
    printf("%u\n",sizeof(+c));  //4
    //c只要参与表达式运算,就会发生整型提升,所以sizeof(+c)是4个字节
    //表达式-c也会发生整型提升,所以sizeof(-c)是4个字节
    printf("%u\n",sizeof(!c));  //4
    return 0;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

会飞的冯猪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值