【c语言操作符详解】


前言

c语言当中有着大量的操作符,本篇文章相较于之前的【初识c语言】中的所讲的操作符做出了对各个操作符的具体内容更加深入的探究。类似 - + = 这种比较简单的这篇文章就不再过多解释了


一、算术操作符(+ - * / %)

除法“ / ”的结果返回的是商;取模“ % ”运算返回的是余数

需要注意的是除法( / ),当 9/2 时,按道理结果应该是 4.5

int main()
{
	int i = 9 / 2;
	printf("%d\n", i);

	return 0;
}

但是实际上输出结果为 4 ,因为 9 和 2 都是int型,所以输出值也是整形,如果要得到小数该怎么做呢 ?

int main()
{
	double i = 9.0 / 2;
	//int i = 9 /2.0;
	printf("%lf\n", i);

	return 0;
}
只要除法两边有一个是 x.0 的形式,结果就是小数型,注意定义和输出的时候类型也
应该用浮点型

二、移位操作符(<< >>)

1. <<左移操作符

左移操作符:
a 的真值为 2,2的二进制序列为 0000 0010(为了方便这里只用八位),左移操作符就是将二进制序列向左移动一位,变成 0000 0100 ,其真值为 4 再左移一次就成了 0000 1000,真值为 8 ,所以,左移操作符的意义就是左移几位,就将变量扩大几倍

int main()
{
	int a = 2;//0000 0010
	a = a << 1;//0000 0100
	printf("%d\n", a);
	return 0;
}//结果为 4 

2. >>右移操作符

右移操作符就和左移操作符逻辑完全一样了,右移几位,缩小几倍
算数右移:右移时高位复制符号位
逻辑右移:右移时高位直接补零

int main()
{
	int a = -1;//1111 1111
	a = a >> 1;//1111 1111
	printf("%d\n", a);
	return 0;
}//结果为 -1  

三、位操作符(& | ^)

※三个操作符的操作数必须为整数

1. & 按位与

同为真 “1” 时 结果为真 “1”

	int i = 3;
	int j = 5;
	printf("%i\n", i & j);// i、j按位与
	//0000 0011
	//0000 0101
	//0000 0001 结果

2. | 按位或

同时为假 “0” 结果为假 “0”

	int i = 3;
	int j = 5;
	printf("%i\n", i & j);// i、j按位与
	//0000 0011
	//0000 0101
	//0000 0111 结果

3. ^ 按位异或

相同则结果为假 “0”
小细节:两次异或可以抵消(a == a ^ b ^ b)

	int i = 3;
	int j = 5;
	printf("%i\n", i & j);// i、j按位与
	//0000 0011
	//0000 0101
	//0000 0110 结果

小练习:交换两个数 a b的值,要求不使用第三个变量

//方法一:
	int a = 3;
	int b = 5;
	a = a + b;//a = 8
	b = a - b;//b = 3
	a = a - b;//a = 5
//方法二:
	int a = 3;
	int b = 5;

	a = a ^ b;//0000 0110
	b = a ^ b;//0000 0011
	a = a ^ b;//0000 0101

作业:编写一个代码实现:求一个整数存储在内存中的二进制中 1 的个数

分析:例如求0000 0111中1 的个数,我们可以运用上面的知识想到,如果给它按位与 1 ,结果刚好是 1 ,因为
0000 0111
0000 0001同时为1 结果为1 .
如果结果是1,那么久计数器+1,如果不是1,那么让被比较的数右移移位继续比较 1。

代码实现: 这里注意循环右移时,while语句的表达式应为 被比较的数 ,等到右移至零,表达式为假刚好跳出循环

int main()
{
	int a = 7;//0000 0111
	int count = 0;
	while (a)
	{
		if (a & 1 ==1)
		{
			count++;
		}
		a = a >> 1;
	}
	printf("%d\n", count);
	return 0;
}//结果为 3 .

四、赋值操作符( = += -= *= /= %= <<= >>=)

赋值操作符可以连续使用(连续赋值)

	int a = 10;
	int b = 0;
	int c = 20;
	a = b = c + 1;//a = b = 21____a = 21
	int a = 20;
	a = a + 10;
	a += 20;//与上面一行意思是一样的

五、单目操作符(! - + & sizeof ~ ++ – (类型))

1. sizeof 计算类型所占空间

单位是字节 B

	int a = 10;
	char arr[10] = { 0 };
	printf("%d\n", sizeof(arr));// 10
	printf("%d\n", sizeof(arr[0]));//1
	printf("%d\n", sizeof a);//4

练习:

	short s = 5;//2字节
	int a = 10;//4字节
	printf("%d\n",sizeof(s = a + 2));//2 由s决定大小,已经在程序编译期间确定
	printf("%d\n", s);//5

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

注意:sizeof计算数组传参问题

我们知道,在数组传参时,传过去的仅仅是数组首元素的地址,既然是地址那么就分为32位或者64位,转为字节单位就是4字节或者8字节,所sizeof计算传参后的数组大小要么是4要么是8

void test1(int* arr)
{
	printf("%d\n", sizeof(arr));//4/8
}

void test2(char* ar)
{
	printf("%d\n", sizeof(ar));//4/8
}

int main()
{

	int arr[10] = { 0 };
	char ar[10] = { 0 };
	printf("%d\n", sizeof(arr));//40
	printf("%d\n", sizeof(ar));//10

	test1(arr);
	test2(ar);
	return 0;
	return 0;
}

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

	int a = -1;
	a = ~a;

	//1111 1111 1111 1111(-1 的补码)

	//按位取反:0000 0000 0000 0000 
	printf("%d\n", a);//结果为 0 

3.前置、后置-- ++

前置:先运算,再使用;
后置:先使用,再运算。

	int a = 10;
	int b = 3;
	printf("%d\n", ++a);//11 a = 11
	printf("%d\n", b--);//3 b = 2

4. * 解引用操作符 & 取地址操作符

	int a = 10;
	&a;//通过&取出a的地址
	printf("%p\n", &a);//000000DA6BAFFA84

如果将这个地址存放在一个空间里的话,如:pa,此时,pa就是指针变量,记作 * pa ,此外a为int型,所以指针变量 * pa也应该为int型:


	int a = 10;
	int* pa = &a;//指针变量*
	*pa = 20;//解引用操作符*
	printf("%d\n",a);//20

5. (类型)强制类型转换

	int a = (int)3.14;
	printf("%d\n", a);//3

六、关系操作符(> < <= >= != ==)

用于判断大小、测试不相等或相等

判断两个字符串是否相等不能用 == ;

应该使用strcmp函数

   strcmp(str_1,str_2); //字符串匹配,返回零说明匹配成功

七、逻辑操作符(&& || )

区分按位与 & 按位或 |

逻辑与&&:只有操作数同时满足才为真

	int a = 10;
	int b = 3;
	if (a > 10 && b < 5)只有当两边同时满足,结果才为真
	{
		printf("hehe\n");
	}//hehe

逻辑或 | | :操作数只要满足其一即可返回真

	int a = 10;
	int b = 3;
	if (a > 10 || b < 5)只有当两边同时满足,结果才为真
	{
		printf("hehe\n");
	}//hehe

练习:代码运行结果?

	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);// 1 2 3 4 

对于&&,int c = a && b;当a已经为假,那么b就不重要了,直接返回假,所以上面的代码只执行了a++。
对于 | | ,int c = a | | b; 当a为真,则直接返回真,后续无需执行,只需要执行a。

八、条件操作符(三目操作符)

1. exp1 ? exp2 : exp3

	int a = 3;
	int b = 0;
	int c = a > 5 ? 1 : -1;
	//a > 5 吗?如果大于,返回1,如果不大于,返回-1

2. 逗号表达式

从左向右依次计算,但是整个表达式的结果是最后一个表达式的结果。

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

九、下标引用操作符([ ])

其作用就是通过下标访问数组元素,使用方法如下:

一个数组名 + 一个索引值

arr[ 3 ]
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

	printf("%d\n", arr[4]);//[]访问数组下标为4的元素,数组默认从零开始,结果为5
	return 0;
}

十、函数调用操作符(())

int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int a = 10;
	int b = 20;
	int ret = Add(a, b);//这个( )符号就是函数调用操作符
	return 0;
}

()函数用操作符接受一个或者多个操作数,第一个操作数是函数名,剩余的操作数就是传递函数的参数。
如:

  test()
  Add(a,b)

十一、结构成员访问操作符

在生活中需要描述一个整体的特征往往是复杂的,这时候就不能局限于c语言中固定的数据类型,因此结构体类型由此诞生,它的作用就是用来描述复杂对象的。在结构体中有多个不同的特征,而所谓结构成员访问,实际上就是对于结构体内复杂元素的访问。
例如,当我们要创建一本书的时候,可以从 书名、书号、定价出发创立一个结构体

struct Book
{
	char name[20];
	char id[20];
	float price;
};

这样看起来,定义结构体就相当于是定义了一本什么都没有的 “ 书 ” ,它只是拥有了 “ 书 ” 的全部特征,而这些特征就需要后面人为的改变他(赋值)去创造出不同的书。

例如

int main()
{
	struct Book shu1 = { "c语言","235446365",12.6};
	printf("书名:%s\n", shu1.name);
	printf("书号:%s\n", shu1.id );
	printf("定价:%f\n", shu1.price );


	return 0;
}

第一种写法:
对于上述代码要注意的是使用结构体就相当于使用int char一样,需要加上变量名。 访问结构体运用的是:点操作符(结构体名 . 成员名

第二种写法:
当拿到的是结构体的地址而不是结构体本身时,使用 -> 来访问结构体元素(结构体指针名 -> 成员名

int main()
{
	struct Book shu1 = { "c语言","235446365",12.6};

	struct Book* pb = &shu1;
	printf("书名:%s\n", pb->name);
	printf("书号:%s\n", pb->id );
	printf("定价:%f\n", pb->price);



	return 0;
}

总结

本片文章基本上涵盖了c语言中常用的操作符,希望本篇能对c语言初学者在对于操作符这块能有所帮助。如有纰漏,欢迎批评指正
如果觉得这篇文章写的不错的话,可以点赞 + 收藏 + 评论支持!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值