【C语言初阶】操作符详解

目录

一.算数操作符:

二.移位操作符:

三.位操作符:

四.赋值操作符:

五.单目操作符:

1.单目操作符的介绍:

2.sizeof和数组:

 六.关系操作符:

七.逻辑操作符:

八.条件操作符:

九.逗号表达式:

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

1.[ ]下标引用操作符:

2.( )函数调用操作符:

3.访问结构体成员:

一.算数操作符:

众所周知数学里面有加,减,乘,除等算数符号。而在C语言中我们也有进行数学运算的符号,叫做算数操作符,但是和数学中的符号还是有一定的区别

算数操作符:

+ 进行两个数的加法运算

进行两个数的减法运算

*  进行两个数的乘法运算

/  进行两个数的除法运算

进行两个数的取余运算

算数操作符中的加减乘和数学中的加减乘作用十一样的,都可以进行整数和浮点数(小数)的运算, 

但是取余操作符 只能参与整数运算,即 % 两边不能有浮点数存在。而 只保留整数部分,5/2是得不到2.5,所以5/2=2。

    int a = 5;
	int b = 2;
	int c = a / b;//只保留整数部分
	int d = a % b;
	printf("a/b=%d\n", c);//结果是c=2
	printf("a%b=%d\n", d);//结果是d=1

二.移位操作符:

移位操作符,移动的是什么呢?其实移动的是二进制补码的位。在这里我们就要学习一下二进制的原码,反码,补码。

一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1。(即最高位为符号位)

原码:就是将一个数的二进制位原原本本的翻译出来。

反码:最高位不变,将数字的原码进行按位取反,0变成1,1变成0

补码:反码+1。

正数的原码,反码,补码相同。

移位操作符:

1.<<左移操作符:左边不要,右边补0。

正数:

int main()
{
	int a = 1;
	//00000000000000000000000000000001-1的补码

	int b = a << 1;//向左移动一位二进制位,右边补0
	//00000000000000000000000000000010-b的值
	printf("%d", b);//由此得出b=2
	return 0;
}

负数:

int main()
{
	int a = -1;
	//10000000000000000000000000000001-原码
	//11111111111111111111111111111110-反码
	//11111111111111111111111111111111-补码

	int b = a << 1;//将a的补码向左移一位,右边补0
	//11111111111111111111111111111110-b的补码
	//11111111111111111111111111111101-b的反码
	//10000000000000000000000000000010-b的原码

	printf("%d", b);//由b的原码得知b=-2
	return 0;
}

 2.>>右移操作符:右移操作符有两种:

第一种:算术右移。右边丢弃,左边用原来的符号位来填充。

第二种:逻辑右移。右边丢弃,左边直接用0补充。

到底我们的编译器到底是那种右移呢?我们不妨来实验一下,这里我们只能用负数来验证,如果是正数,左边都是补的0,看不出差别。

int main()
{
	int a = -5;
	//10000000000000000000000000000101-原码
	//11111111111111111111111111111010-反码
	//11111111111111111111111111111011-补码

	int b = a >> 1;
	//算数右移:
	//11111111111111111111111111111101-补码
	//11111111111111111111111111111100-反码
	//10000000000000000000000000000011-原码
	//得出b=-3
	
	//逻辑右移:
	//01111111111111111111111111111101-补码
	//01111111111111111111111111111100-反码
	//00000000000000000000000000000011-原码
	//得出b=3
	printf("%d", b);

	return 0;
}

由结果可知,右移操作符执行的是算术右移,即右边丢弃,左边用原来符号位来填充。

三.位操作符:

& 按位与

|   按位或

^  按位异或

 位操作符都是两个数的补码进行计算。

& 按位与:全1为1,不同为0

|   按位或:有1为1,全0为0

^  按位异或:相同为0,不同为1

按位与:&

int main()
{
	int a = 3;
	//00000000000000000000000000000011
	int b = -5;
	//10000000000000000000000000000101-原码
	//11111111111111111111111111111010-反码
	//11111111111111111111111111111011-补码
	int c = a & b;//补码进行运算
	//00000000000000000000000000000011
	//11111111111111111111111111111011
	//00000000000000000000000000000011-c的补码
	//因为最高位是0,即c为整数,原反补码相同
	printf("%d", c);//c=3
	return 0;
}

 按位或:|

int main()
{
	int a = 3;
	//00000000000000000000000000000011
	int b = -5;
	//10000000000000000000000000000101-原码
	//11111111111111111111111111111010-反码
	//11111111111111111111111111111011-补码
	int c = a | b;//补码进行运算
	//00000000000000000000000000000011
	//11111111111111111111111111111011
	//11111111111111111111111111111011-c的补码
	//11111111111111111111111111111010-c的反码
	//10000000000000000000000000000101-c的原码
	printf("%d", c);//c=-5
	return 0;
}

 按位异或:^

int main()
{
	int a = 3;
	//00000000000000000000000000000011
	int b = -5;
	//10000000000000000000000000000101-原码
	//11111111111111111111111111111010-反码
	//11111111111111111111111111111011-补码
	int c = a ^ b;//补码进行运算
	//00000000000000000000000000000011
	//11111111111111111111111111111011
	//11111111111111111111111111111000-c的补码
	//11111111111111111111111111110111-c的反码
	//10000000000000000000000000001000-c的原码
	printf("%d", c);//c=-8
	return 0;
}

 按位异或结论:两个相同的数异或,结果为0。任何数异或0,结果为0。

我们学习位操作符有什么具体的用处吗?

当我交换两个整数时,可以使用异或操作符来实现:

常规方法:

int main()
{
	int a = 3;
	int b = 5;
	printf("交换前:a=%d,b=%d\n", a, b);
	int temp = a;
	a = b;
	b = temp;
	printf("交换后:a=%d,b=%d", a, b);
	return 0;
}

按位异或:

int main()
{
	int a = 3;
	int b = 5;
	printf("交换前:a=%d,b=%d\n", a, b);
    //用上异或的结论
	a = a ^ b;
	b = a ^ b;//b=a^b^b=a
	a = a ^ b;//a=a^b^a=b
	printf("交换后:a=%d,b=%d", a, b);
	return 0;
}

四.赋值操作符:

赋值就是将常量的值赋值给变量。

int main()
{
	int a = 1;
	int b = 2;
	int c = b = a + 1;//将a+1的值赋值给b,b再赋值给c
    //我们不妨写成b=a+1;c=b;这样看起来更加清楚
	return 0;
}

复合赋值符:

int main()
{
	int a = 3;
	a = a + 2;
	//a+=1;
	a = a - 2;
	//a-=1;
	a =a*2;
	//a*=2;
	a = a % 2;
	//a%=2;
    //它们都是等价的
    //还有^=,&=,>>=,<<=等等 
	return 0;
}

五.单目操作符:

1.单目操作符的介绍:

! 逻辑反操作

-   负值

+  正值

&  取地址

~  按位取反

--  前置,后置--

++  前置,后置++

*   间接访问操作符(解引用操作符)

sizeof   求字节长

 !逻辑反操作:

int main()
{
	int a = 1;
	if (a)//a为真就执行下面的语句
	{
		printf("hehe\n");
	}
	if (!a)//a为假时,!a就为真,执行下面的语句
	{
		printf("haha\n");
}
	return 0;
}

*解引用,&取地址:

int main()
{
	int a = 1;
	int* pa = &a;
	//地址用指针接收
	printf("a的地址为%x\n", &a);
	printf("a的值为%d\n", *pa);
	//*pa解引用找到pa地址指向的值
	return 0;
}

 ~按位取反操作符:

int main()
{
	int a = 1;
	//00000000000000000000000000000001-a的补码
	int b = ~a;//按位取反,包括符号位
	//11111111111111111111111111111110-b的补码
	//11111111111111111111111111111101-b的反码
	//10000000000000000000000000000010-b的原码
	printf("%d", b);//所以b=-2
	return 0;
}

 前置--和后置--,前置++和后置--:

当我们写成--a时,就是前置--,我们应当先把a-1了之后,再使用a的值。

而后置就是完全相反,当我们写成a--时,就是后置--,我们应当先把使用a的值,再把a-1赋值给a。

int main()
{
	int a = 2;
	int b = a--;
	//先使用a的值赋值给b,再将a-1的值赋值给a
    //所以a=1,b=2
	printf("a=%d b=%d",a, b);
	return 0;
}
int main()
{
	int a = 2;
	int b = --a;
	//先使用a-1的值赋值给b,再将a-1的值赋值给a
    //所以a=1,b=1
	printf("a=%d b=%d",a, b);
	return 0;
}

2.sizeof和数组:

int main()
{
	int a = 1;;
	printf("%d\n", sizeof(int));//int类型,4个字节
	printf("%d\n", sizeof(a));
	int arr[10] = { 0 };
	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof(arr[1]));
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d\n", sz);
	return 0;
}

void test1(int arr[])
{
	printf("%d\n",sizeof(arr));//这里也是40吗
}
void test2(char ch[])
{
	printf("%d\n", sizeof(ch));//这里也是10吗
}
#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("%d\n", sizeof(arr));
	//这里sizeof中的arr整个数字,所以是40
	printf("%d\n", sizeof(ch));//这里是10
	test1(arr);
	test2(ch);
	return 0;
}

 

 上面函数部分sizeof求出来的为什么和主函数的不一样呢?因为函数传参的时候,传的是地址,应该用指针接收,但是可以写成这种数组的形式,只是为了方便观察,所以这里求得是指针的大小,在x86平台是4个字节,在x64平台是八个字节

 六.关系操作符:

>

>=

<

<=

==

!=

 我们在条件语句中,写的就是关系操作符,如:

int main()
{
	int a = -1;
	if (a ==1)//判断a是否和1相等
		//不能写成if(a=1)
	{
		printf("hello");
	}
	return 0;
}

七.逻辑操作符:

&& 逻辑与

| |  逻辑或

这里要区分逻辑操作符和位操作符,这两者是没有关系的,逻辑操作符只判断真假。

int main()
{
	int a = 2&&3;
	//2和3都为真,逻辑与起来也是真,所以a=1
	printf("%d\n", a);
	int b = 1 || 0;
	//1为真,0为假,逻辑或起来为真,所以b=1
	printf("%d\n", b);
	int c = 5 && 0;
    //5为真,0为假,逻辑与起来为假,所以c=0
	printf("%d\n", c);
	return 0;
}

 我们来看一道笔试题:

int main()
{
	int i = 0, a = 0, b = 1, c = 2, d = 4;
	i = a++ && ++b && c++;
      //这里a++为0
	printf("a=%d b=%d c=%d d=%d", a, b, c, d);
	return 0;
}

如果我们不是很仔细或者不了解逻辑与&&的含义,这道题很有可能就会做错。

错误理解:

首先我们a++,先使用a,再++,所以打印出来a=1;

接下来++b,先把b+1赋值给b,再使用b,所以打印出来b=2;

然后c++,先使用c,再++,所以打印出来c=3;

最后打印出来就是1 2 3 4

 结果却是1 1 2 4,这是为什么呢?这里我们就要理解逻辑与&&的作用了,在a++时,为后置++,先使用再变值,所以表达式中a++为0,逻辑与上后面的表达式为假,所以代码压根就不会执行后面的代码。所以我们一定要清楚每一个符号的含义。

八.条件操作符:

exp1?exp2:exp3

 这其实就是三目操作符,当exp1为真时,执行exp2,否则执行exp3

我们可以用三目操作符来比较两个数的最大值:

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

九.逗号表达式:

逗号表达式:就是用逗号隔开的多个表达式,从左到右依次计算,最后的结果是最后一个表达式的结果。

int main()
{
	int a = 1;
	int b = 3;
	int c = (a++, a=b-2, a + 5);
	//a++=1,然后a=2,之后a=3-2=1;所以a+5=6
	printf("%d\n", c);//c就是6
	return 0;
}

一些比较复杂的代码,我们有时可以使用逗号表达式来代替。

int main()
{
	int a = 10;
	a = test1();
	test2(a);
	while (a)
	{
		a = test1();
		test2(a);
	}
	return 0;
}

替换:

int main()
{
	int a = 10;
	while (a = test1(), test2(), a)
	{
		;
	}
	return 0;
}

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

1.[ ]下标引用操作符:

操作数:一个数组名和一个下标数。

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d", arr[5]);
	//这里的arr和5就是操作数,使用下标操作符访问到下标为5的元素
	return 0;
}

2.( )函数调用操作符:

接受一个或多个操作数:第一个操作数是函数名,剩余的操作数就是传递个函数的参数。

int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int a = 3;
	int b = 4;
	int num = Add(a, b);//( )就是函数调用操作符
	 //Add和参数a,b就是操作数
	printf("%d\n", num);
	return 0;
}

3.访问结构体成员:

1.结构体变量.结构体成员名

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

struct s
{
	int num;
	char b;
	double c;
};
void test(struct s* pS)//参数为地址,用指针接收
{
	printf("%d %c %.2lf\n", pS->num, pS->b, pS->c);
	//用结构体指针来访问结构体成员使用->
}
int main()
{
	struct s S = { 10,'B',3.14 };//用大括号
	//S是结构体变量
	printf("%d %c %.2lf\n", S.num, S.b, S.c);
	//用结构体变量来访问结构体成员使用.
	test(&S);
	return 0;
}

这就是全部的内容,希望能给你带来一点点收获。还望一键三连。感谢! 

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值