学习干货速进,小白都能看懂的C语言操作符详解

操作符详解


分类:

算术操作符
移位操作符
位操作符
赋值操作符
单目操作符
关系操作符
逻辑操作符
条件操作符
逗号表达式
下标引用、函数调用和结构成员

算数操作符

+  -  *  /   %
#include<stdio.h>
int main()
{
	//int a = 6 / 5;
	//printf("%d\n", a);//1

	//float a = 6 / 5;
	//printf("%f\n", a);//1.00000

	float a = 6.0 / 5;
	printf("%f\n", a);//1.2
	return 0;
}

6/5算的结果就是商–1,所以把a改为float也没用,只能将6/5改为6.0/5或6/5.0或者6.0/5.0。

int main()
{
	int a = 7 % 3;
	printf("%d\n", a);//1
	return 0;
}

1.除了%外,其他都能对整形或者浮点数进行运算

2.对于/操作符如果两个操作数都为整数,则执行整数除法,只要里面有浮点数则进行的是浮点数除法

3.%操作符的两操作数必须为整数,返回的是余数

求一个整数存储在内存中的二进制中1的个数

移位操作符

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

左移操作符:

左边抛弃、右边补0

int main()
{
	int a = 2;
	//把a的二进制位向左移动一位,最左边丢弃,右边加0
	//00000000000000000000000000000010
	//00000000000000000000000000000100---4
	int b = a << 1;
	printf("%d\n", b);//4
	return 0;
}

image-20210507231324912

右移操作符:

首先右移运算分两种:

  1. 逻辑移位 左边用0填充,右边丢弃
  2. 算术移位 左边用原该值的符号位填充,右边丢弃
int main()
{
	int a = 10;
	//把a的二进制数向右移动一位
	//00000000000000000000000000001010
	//1.逻辑移位 左边用0填充,右边丢弃
	//00000000000000000000000000000101---5
	//2.算术移位 左边用符号位填充,右边丢弃
	//00000000000000000000000000000101---5
	int b = a >> 1;
	printf("%d\n", b);//5
	return 0;
}

image-20210507231851200

负数可以测试出是算术移位还是逻辑移位

int main()
{
	int a = -1;
	//把a的二进制数向右移动一位
	//11111111111111111111111111111111
	//逻辑右移
	//01111111111111111111111111111111
	//00000000000000000000000000000001----1 原码
	//算术右移
	//11111111111111111111111111111111
	//10000000000000000000000000000001-----  -1 原码
	int b = a >> 1;
	printf("%d\n", b);//-1  可以看出用的是算术右移
	return 0;
}

image-20210507232334886

可以看出采用的是算术右移。

注意:对于移位运算符,不要移动负数位,这个是标准未定义的。

位操作符

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

按位与

int main()
{
	int a = 3;
	int b = 5;
	//& - 按(二进制)位与
	int c = a & b;
	//00000000000000000000000000000011
	//00000000000000000000000000000101
	//00000000000000000000000000000001  -- 1
	printf("%d\n", c);
	return 0;
}

image-20210507233509457

按位或

int main()
{
	int a = 3;
	int b = 5;
	//& - 按(二进制)位与
	int c = a | b;
	//00000000000000000000000000000011--a
	//00000000000000000000000000000101--b
    //每一位进行或
	//00000000000000000000000000000111  -- 7
	printf("%d\n", c);
	return 0;
}

image-20210507233629711

按位异或

int main()
{
	int a = 3;
	int b = 5;
	//& - 按(二进制)位与
	int c = a ^ b;
	//00000000000000000000000000000011--a
	//00000000000000000000000000000101--b
    //每一位进行异或--相同为0,不同为1
	//00000000000000000000000000000110  --6
	printf("%d\n", c);//6
	return 0;
}

image-20210507233901091

一道面试题:

不借助临时变量将两个变量的值交换

int main()
{
    int a=3;
    int b=5;
    printf("a=%d b=%d",a,b);
    
    a=a^b;       //a^b^b=a  a^b^a=b								
    b=a^b;
    a=a^b;
    return 0;
}

求一个整数存储在内存中的二进制中1的个数

//int a=7;
//00000000000000000000000000000110
//123
//123%10  得到3
//123/10=12 去掉3
// %10 /10
int count_one(int n)
{
    int count=0;
    while(n)//n如果不是0,二进制序列一定有1
    {
        if(n%2==1)
        {
            count++;
        }
        n=n/2;
    }
    return count;
}
int main()
{
    int a=6;
    int ret=count_one(a);
    printf("%d\n",ret);
    return 0;
}

这个代码有问题的,如果a=-1时,编译的1的个数为0,

int count_one(int n)
{
   int count=0;
    int i=0;
    for(i=0;i<32;i++)
    {
        if(((n>>i)&1)==1)
        {
            count++;
        }
    }
    return count;
}
int main()
{
    int a=-1;
    //原码:10000000000000000000000001
    //反码:11111111111111111111111110
    //补码:11111111111111111111111111
    //内存中存的是补码
    //让这个数字和1按位与
    //11111111111111111111111111111111
    //00000000000000000000000000000001
    //00000000000000000000000000000001
    //最后一位为1得到1,最后一位为0得到0
    int ret=count_one(a);
    printf("%d\n",ret);
    return 0;
}

上面的代码一定会循环32次,下面这个代码更高效

//n=n&(n-1)
//每一次都让二进制序列中最右边的1消失
//在n变成0之前,让n=n&(n-1),这个操作执行一次count++
//n=7
//111-n
//110
//110-n
//101
//100-n
//011
//000-n
int count_one(int n)
{
    int count=0;
	while(n)
    {
        n=n&(n-1);
        count++;
    }
    return count;
}
int main()
{
    int a=-1;
    int ret=count_one(a);
    printf("%d\n",ret);
    return 0;
}

赋值操作符

int main()
{
    int a=0;
    a=3;//赋值操作符
    
    //与==容易混淆,判断是否相等
}

赋值操作符可以连续赋值,但是不建议

int main()
{
    int a=10;
    int x=0;
    int y=20;
    a=x=y+1;
    return 0;
}

复合赋值符

int main()
{
    int a=0;
    a=a+3;
    a+=3;//简单明了
    
    a=a-10;
    a-=10;
    
    a=a>>1;
    a>>=1;
    
    a=a&1;
    a&=1;
}

单目操作符

int main()
{
    3+5;//+ 有两个操作数 双目操作符
    //单目操作符-只有一个操作数的操作符
    
    return 0;
}

!逻辑反操作

int main()
{
    int a=10;//10-非零-真
    printf("%d\n",!a);//0
    //把真变成假,假变成真
    int flag=1;
    if(!flag)//flag为假时进来
    {
        
    }
}

-负值操作符

int main()
{
    int a=-10;
    a=-a;
    a=+a;//正号可以省略
}

&取地址操作符

int main()
{
    int a=10;//4个字节空间
    int* pa=&a;//拿到了a的地址,指针变量
    printf("%p\n",&a);//&-取地址操作符
    return 0;
}

*解引用操作符

int main()
{
    int a=10;//4个字节空间
    int* pa=&a;//拿到了a的地址,指针变量
    *pa=20;//*解引用操作符,拿到a 
    return 0;
}

sizeof操作符

操作数的类型长度(单位是字节)

int main()
{
    int a=10;
    int arr[10]={0};
    printf("%d\n",sizeof(arr));//计算数组的总大小
    printf("%d\n",sizeof(int[10]));
    printf("%d\n",sizeof(a));//4
    printf("%d\n",sizeof(int));//4
    return 0;
}
int main()
{

	short s = 5;
	int a = 10;
	printf("%d\n", sizeof(s = a + 2));//2 这里没有参与运算,没有整形提升
	printf("%d\n", s);//5
	return 0;
}

image-20210509100225328

sizeof括号中放的表达式是不参与运算的!

a+2的结果不一定会放入s里面,但是如果放进去,这个表达式的类型s说了算。

#include <stdio.h>
void test1(int arr[])
{
	printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
	printf("%d\n", sizeof(ch));//(4)
}
int main()
{
    int arr[10] = {0};
    char ch[10] = {0};
    printf("%d\n", sizeof(arr));//(1)
    printf("%d\n", sizeof(ch));//(3)
    test1(arr);
    test2(ch);
    return 0;
}
问:
(1)、(2)两个地方分别输出多少?
(3)、(4)两个地方分别输出多少?

image-20210508183844859

我们将数组名进行传参时,传过去的是首元素的地址,地址得用指针来接收,其实函数参数本质上是个指针,大小是4(32位)或者8(64位)。

~操作符

对一个二进制位按位取反

int main()
{
    int a=0;
    printf("%d\n",~a);
    //00000000000000000000000000000000
    //按位取反
    //11111111111111111111111111111111补码
    //%d打印的是原码
    //11111111111111111111111111111110反码
    //10000000000000000000000000000001原码
    //-1
    return 0;
}
int main()
{
    int a=14;
    a|=(1<<4);
    printf("%d\n",a);
    
    a&=(~(1 << 4));
    printf("%d\n",a);
    //00000000000000000000000000001110 将第五位变为1
    //00000000000000000000000000010000
    //按位或
    //00000000000000000000000000011110 将第五位再变回0
    //11111111111111111111111111101111
        //按位与则将第五位变回0,其他位不变
    return 0;
}

++ --操作符

int main()
{
    //a++是表达式
    int a=10;			//a++表达式先使用a的值,a再++
    int b=a++;//后置++   //先使用a,再++
    printf("a=%d b=%d\n",a,b);//11 10
    
    int b=++a;//前置++   先++,后使用a
    printf("a=%d b=%d\n",a,b);//11 11
    return 0;
    
    int a=10;
    int b=a--;//后置--   //先使用a,再--
    printf("a=%d b=%d\n",a,b);//
    
    int a=10;
    int b=--a;//前置--   //先--,再使用a
    printf("a=%d b=%d\n",a,b);//
    
    int a=10;
    printf("%d\n",a++);
}
int main()
{
    int a=1;
    int b=(++a)+(++a)+(++a)
    printf("%d\n",b);
    return 0;
}

错误代码,vs环境编译为12,Linux环境编译为10。

(类型)强制类型转换

int main()
{
    int a=3.14;
    printf("%d\n",a);
    return 0;
}

会出现警告,不想出现警告,可以这样做

int main()
{
    int a=(int)3.14;
    printf("%d\n",a);
    return 0;
}

关系操作符

>
>=
<
<=
!=
==

在编程中小心==和=不小心写错导致错误

一些关系不能用关系操作符比较的:

例如字符串的比较

逻辑操作符

&&逻辑与

||逻辑或

逻辑与和逻辑或只看真假

int main()
{
    int a=3;
    int b=5;
    //a&b;//按二进制位与
    //a&&b;//逻辑与
    int c=a&&b;//a,b都为真,c才为真
    printf("%d\n",c);
    return 0;
    
}
int main()
{
    int a=0;
    int b=5;
    int c=a||b;//只要有一个真则为真
    printf("%d\n",c);
    return 0;  
}
int main()
{
    int i=0,a=0,b=2,c=3,d=4;
    i = a++ && ++b && d++;
    printf("a=%d b=%d c=%d d=%d",a,b,c,d);//1 2 3 4
    return 0;
}

注意:对于&&操作符,左边如果为零,编译器就不会计算右边了

对于||操作符,左边如果为1,右边就不计算了

条件操作符

三目操作符-三个操作数

表达式1?表达式2:表达式3

表达式1为真,算的是表达式2的结果,否则为表达式3的值

int main()
{
    int a=10;
    int b=20;
    int max=0;
    max=a>b?a:b;
    return 0;
}

逗号表达式

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

int a=1;
int b=2;
int c=(a>b,a=b+10,a,b=a+1);//逗号表达式

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

下标引用

int main()
{
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    //arr+4
    printf("%p\n",arr+4);//%p是打印地址的
    printf("%p\n",&arr[4]);
    
    printf("%d\n",*(arr+4));
    
    printf("%d\n",arr[4]);//下标引用操作符
    printf("%d\n",4[arr]);//下标引用操作符
    
    //*(arr+4) == arr[4]
    //*(4+arr) == 4[arr]
    return 0;
}

函数调用

int main()
{
    printf("haha");//()函数调用操作符
    return 0;
}

访问一个结构的成员

struct Book
{
  	char name[20];
    int price;
};
int main()
{
    struct Book b={"C语言",30};
    //结构体变量.成员变量
    printf("书名:%s  定价:%d\n",b.name,b.price);
    
    struct Book* pb=&b;
    //结构体指针->成员变量
    printf("书名:%s  定价:%d\n",pb->name,pb->price");
    return 0;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小赵小赵福星高照~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值