【C语言】 操作符的困惑都在这里解决! (操作符详细解析)

前言:

本文是C语言操作符详解篇,可以帮助新手小白,快速了解c语言操作符的使用方法,每一个操作符都有列子和解释,做以参考学习。


算术操作符

加:+
减 : -
乘: *
除: /
取余:%

  1. 加法:+ 加法没有什么好说的,和数学的加法一样

例题:

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

在这里插入图片描述
解释:C语言加法和数学加法一样的,1 + 2 = 3;


  1. 减法:- 减法没有什么好说的,和数学的减法一样
    例题:
int main()
{
    
    
	int a = 3;
	int b = 2;
	printf("%d", a - b);
	return 0;
}

在这里插入图片描述
解释:C语言减法和数学减法一样的,3 - 2 = 1;


  1. 乘法: *
    c语言中的乘法,并不是像数学那样是个 x ,而是一个小雪花(*)

    例:

int main()
{
    
    
	int a = 3;
	int b = 2;
	printf("%d", a * b);
	return 0;
}

在这里插入图片描述
解释: 乘法都是一样的,和数学的一样。


  1. 除法:- 除法:/ ,和数学的÷不同,c语言的是一个左斜杠

注意:c语言的除法,结果往往并不是那么顺人心意的,使用方法和数学的除法不那么一样,具体使用方法要看你操作的数据类型

例:

思考一下下面代码,a等于多少呢?

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

答案:是1,为什么不是1.5呢? 有人会说 int 类型的a,输出出来的肯定是1啊,自然把那个0.5给抹掉了,那我们下面换一个类型看看是多少?

例:

int main()
{
    
    
	float a = 3 / 2;
	
	printf("%f\n", a);
	return 0;
}

答案:1.000000 ,还是1,为什么不是1.5呢? 其实问题出现在 3 / 2 ,这两个数字都是整型的,你要是实在想要一个小数的出现的话可以把3或者2加个小数,比如 3/2.0.

int main()
{
    
    
	float a = 3 / 2.0;
	
	printf("%f\n", a);
	return 0;
}

在这里插入图片描述

结论:你要是想得到一个小数,除数 或 被除数至少有一个是浮点数。

注:float类型不加f,会报警告:正确格式应该是:float a = 3 / 2.0f;


  1. 取余:% 操作符的两个操作数必须为整数。返回的是整除之后的余数

例:

int main()
{
    
    
	int a = 7 % 3;

	printf("%d\n", a);
	return 0;
}


答案:1,因为是取余,和数学那个余数是一样的,所以是1


移位操作符

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

  • << 左移操作符

例:以下代码b输出的是什么?

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

答案: 4,不懂请看下面的详解:

解:
要想知道什么是4,先了解左移是移的什么?
其实上面的左移是把2的二进制位给想向左移动了一位
int a = 2;
int 类型是int,在内存占4个字节,也就是32位bit
在这里插入图片描述
现在我们要向左移动一个二进制位,效果如下
在这里插入图片描述
可以看见左边的0 溢出了 ,右边少了一个0,这个时候我们要补回来
在这里插入图片描述
补回来可以看见1到第三位去了,这个时候的二进制位其实是4了,最后得4,这个就是答案,如果看不出来为什么是4 请记住 8421
在这里插入图片描述
结论:左移操作符,左边丢弃,右边补0


  • >>右移操作符

例:以下代码b输出的是什么呢

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

答案:5,不懂请看下面解析:

解析:先要知道a的二进制数:
在这里插入图片描述
向右移动一位
在这里插入图片描述
右边那个0溢出,我们舍弃,那我们左边应该补什么呢?

其实我们已经有2种情况:

1.算数右移
右边丢弃,左边补原符号位

2.逻辑右移
右移丢弃,左边补0

我们当前这个数是正数,大家要知道一个知识点,正数在内存中二进制位最高位是0,所以我们当前情况直接补0就可以了,4+1 等于5 所以是五,当然这个列子不直观,并不可以表达出来,它是算数右移,还是逻辑右移,所以我们来看下面的列子。
在这里插入图片描述

例2: 以下b是多少呢

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

答案:-1,不懂情看解释。

解:
这里我们要引出一个知识点了


针对负数:
整数的二进制表示形式:其实有3种
原码: 直接根据数组写出的二进制序列就是原码
反码: 原码的符号位不变,其他位按位取反就是反码
补码: 反码加1,得到补码

针对正数:
原码,反码,补码相同


-1在内存中存放的是补码

负数的二进制最高位是1,正数二进制位最高位是0

来看看-1的二进制位,就是它的补码
在这里插入图片描述

在这里插入图片描述
我们可以在编译器中跑一下看看最后是大数字还是小数字,因为大数字的话最高位补0是正数,所以是逻辑右移,如果是-1那证明它最高位是补1是负数,证明是算术右移。
来看看结果:
在这里插入图片描述


位操作符

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


1.& -按位(二进制位)与

例:思考一下这个c是什么结果

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

答案:1,不懂看下面解析

解:先看看他们两个数的二进制符号
在这里插入图片描述
规则:只要一个是0就是0,全1才是1,所以得出一个
在这里插入图片描述
最后结果是1。


2.& -按位(二进制位)或

例:思考下面代码打印出来是什么?

int main()
{
    
    
	int a = 3;
	int b = 5;
	int c = a | b;
	printf("%d\n", c);
	return 0;
}

答案:7,不懂看下面解释:

规则:只要一个是1就是1,全0才是0
在这里插入图片描述

所以是7。


3.& -按位(二进制位)异或

例:

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

答案:6,不懂看下面解析

解:规则:相同为0,相异为1
在这里插入图片描述

所以是6


那么这些东西有什么用呢?
我们来看一下一个公司的面试题目

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

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

简单的分析一下,来个其他的例子

int main()
{
    
    
	int a = 3;
	a ^ a;
	0 ^ a;

	return 0;
}

在这里插入图片描述

a ^ a =0;
0 ^ a =a;
在这里插入图片描述
相同的异或等于0
0可以反推回来 a;


例2:


赋值操作符

赋值操作符是一个很棒的操作符,他可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值

int weight = 120;//体重
weight = 89;//不满意就赋值
double salary = 10000.0;
salary = 20000.0;//使用赋值操作符赋值。
赋值操作符可以连续使用,比如:
int a = 10;
int x = 0;
int y = 20; a = x = y+1;//连续赋值
这样的代码感觉怎么样?
那同样的语义,你看看:
x = y+1; a = x;
这样的写法是不是更加清晰爽朗而且易于调试。

单目操作符

! 逻辑反操作
- 负值
+ 正值
sizeof 操作数的类型长度(以字节为单位)
– 前置、后置–
++ 前置、后置++
(类型) 强制类型转换

1. sizeof( 操作数的类型长度(以字节为单位))
在这里插入图片描述

int main()
{
    
    
	int a = 10;
	int arr[10] = {
    
     0 };
	printf("%d\n",sizeof(a));  // 一个字节的大小 输出4, 因为int 是4个字节
	printf("%d\n", sizeof a);      //可以省略括号 ,也证明了sizeof不是一个函数 是一个操作符
	printf("%d\n",sizeof (int));   //int的括号不可以省略
	printf("%d\n", sizeof(arr)); //arr有10个 ,类型是 int[10] 所以是40
	printf("%d\n",sizeof(int [10]));//这个是数组的类型所以也可以
	return 0;
}

来个题目:
思考下题

int main()
{
    
    
	short s = 5;
	int a = 10;
	printf("%d\n",sizeof(s = a + 2));
	printf("%d\n",s);
	return 0;
}

答案:2,5 不懂看下面

解析:
(1)sizeof括号的表达式是不参与运算的
来看一个图
在这里插入图片描述
sizeof(s = a + 2)这个表达式只会在运行的时候开始,我们在编译的时候表达式并没有开始


2.~(二进制取反)
例子 思考下面的题b是多少:

int main()
{
    
    
	int a = -1;
	int b = ~a;
	printf("%d\n",b);
	return 0;
}

答案: 0,解析在下

解:
~ 对一个数的二进制取反
int a = -1,我们来看一下 -1的补码
在这里插入图片描述
可以看见补码是全1 ,取反变成全0
在这里插入图片描述
所以最后是0;


3.–(前置,后置)
例:

int main() 
{
    
    
	int a = 10;
	int b = a++;  //后置++,先使用,再++
	printf("%d\n",a);//11
	printf("%d\n",b);//10

	return 0;
}

前置++

int main() 
{
    
    
	int a = 10;
	int b = ++a;  //前置++,先++,后使用
	printf("%d\n",a);//11
	printf("%d\n",b);//11

	return 0;
}

来个例题:
后置–

int main()
{
    
    
	int a = 10;
	int b = a--;     //在这一步 a--还是10,要先使用,就是先赋值给b ,然后在自减
	printf("%d\n",a);//到这里 自减已经完成了, 所以它是9
	printf("%d\n",b);//一开始就把10赋值过去了 所以b是10

	return 0;
}

在来一个例:

int a =10;
printf("%d\n",a--);  //先使用 a现在还是10
printf("%d\n",a);	//使用完成 a在上一步已经减减 a是9

好了 ++ – 这些了解在这里,不建议大家深入去研究,没有太多好处来看下一部分.


*4. & * (&取地址、解引用)

我们都知道我们创建的变量函数,在内存中都是有自己的位置的,有位置的话,我们要找到他们进行操作是不是需要找到它的地址(&取地址),找到地址是不是要去找到它的实际的数值(*)进行操作,我们来看看下面的代码,和一个模拟代码在内存的图。

int main()
{
    
    
	int a = 10;
	printf("%p\n",&a);//取出a的地址
	int *pa = &a ;//pa是用来存放地址的 
	//-- pa就是一个指针变量 类型是int *
	*pa = 20 ;//解引用操作符,或者间接访问操作符
	//把a改变20;
	printf("%d\n",a); //20
	return 0;
}

在这里插入图片描述
有的人有疑惑 &这个不是按位与吗?为什么变成了取地址了,其实 &是按位与,但是要当两边有 整数才是,&a这样就是取地址。


5.强制类型转换 ()

int main()
{
    
    
	int a = 7.0;
	return 0;
}

这样的代码会报一个警告,说类型double转换到int 数据会丢失。
在这里插入图片描述
因为7.0默认是double,存放到int里面去,就会报警告,想让它不报警告,可以也转换一下,看下图
在这里插入图片描述
这样就不会报警告了,把它强制转换变成了 int 类型的7.


关系操作符

=
<
<=
!= 用于测试“不相等”
== 用于测试“相等”

= 赋值

== 判断相等
字符串相等不可以使用等号来比较。


逻辑操作符

逻辑操作符只判断真假
&& 逻辑与
|| 逻辑或

思考以下代码,输出什么:

int main()
{
    
    
	int a = 3;
	int b = 0;
	if (a&&b)
	{
    
    
		printf("打印我\n");
	}
}

在这里插入图片描述

什么都没有,因为b = 0,0在c语言是false &&必须2个条件为真,才进入。

逻辑或(||)
思考以下代码,输出什么:

int main()
{
    
    
	int a = 3;
	int b = 0;
	if (a||b)
	{
    
    
		printf("打印我\n");
	}
}

在这里插入图片描述
逻辑或,一个为真,就都为真,全假为假

来一个面试题,以下答案是多少呢?

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

答案
在这里插入图片描述
为什么呢?
在这里插入图片描述
因为第一个a后置加加 ,是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++;
i = a++||++b||d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0;
}

答案
在这里插入图片描述
为什么?
逻辑或 1个是0 ,另外一个是真, 那么真的后面就不要运算了.

一开始 a++ 是0,那么要后面还是要运算的 ,当到b不是0,为真时,后面的表达式就不需要运算了,所以是上面的答案


条件操作符

条件操作符也叫做三目操作符

在这里插入图片描述

a>5 ? a: b
//a大于5吗,如果大于 表达式 的值是a ,否则就是b

逗号表达式

以最后一个表达式为结果 要从左向右依次计算

下面代码结果是什么?

int main()
{
    
    
	int a = 3;
	int b = 5;
	int c = 0;
	int d = (c = 5, a = c + 3, b = a - 4 ,c += 5);
	printf("%d\n",d);

}

在这里插入图片描述
C=5 a=8 b=4 5=c+5 =10
所以结果是最后表达式的结果10


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

1.[ ] 下标引用操作符

操作数:一个数组名 + 一个索引值

我们都知道数组下标index是从0开始的,下面代码定义了arr[10],那么下访问最后一个元素应该是arr[9]

int arr[10]={
    
    1,2,3,4,5,6,7,8,9,10};//创建数组
printf("%d\n",arr[9]);
//[ ]的两个操作数是arr和9

2.( ) 函数调用操作符 接收一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数

#include <stdio.h>
void test1()
{
    
    
printf("hehe\n");
}
void test2(const char *str)
{
    
    
printf("%s\n", str);
}
int main()
{
    
    
test1(); //实用()作为函数调用操作符。
test2("hello bit.");//实用()作为函数调用操作符。
return 0;
}

3.访问一个结构的成员

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

在c语言中 有许多类型,比如int float等等,但是我们要是想要定义一本书,那么那个书是什么类型呢?int吗?float吗?好像都不可行,所以C语言给了我们一个能力,自己创建一个类型,struct,看下面代码

. 点操作符

//创建了一个自定义的类型
struct book
{
    
    
	//成员变量
	char name[20];
	char id[20];
	int price;

};

int main()
{
    
    
	//创建了一本书,名字叫b
	//struct book 这个是类型
	struct book b = {
    
     "c语言","2010201", 55 };
	printf("书名:%s\n",b.name);
	printf("书号:%s\n", b.id);
	printf("书价:%d\n", b.price);


	return 0;
}

在这里插入图片描述

  • 使用指针访问结构体成员
//创建了一个自定义的类型
struct book
{
    
    
	char name[20];
	char id[20];
	int price;

};

int main()
{
    
    
	//创建了一本书,名字叫b
	//struct book 这个是类型
	struct book b = {
    
     "c语言","2010201", 55 };
	struct book* pb =&b ;
	//使用指针
	printf("书名:%s\n",pb->name);
	printf("书号:%s\n", pb->id);
	printf("书价:%d\n", pb->price);


	return 0;
}

在这里插入图片描述
如果使用拿到的是地址,就使用指针来指向,找到成员。


好了以上就是c语言基础操作符的介绍,大家可以自己多看看,有不好的地方请大家评论区了评论出来,会重新编写,达到一个最好的效果。

猜你喜欢

转载自blog.csdn.net/qq_46874327/article/details/116593384