一文带你吃透操作符,你还不了解操作符吗?(C语言深入解剖篇)

作者介绍:友友们好我是沐曦希,可以叫我小沐💕
作者主页:沐曦希的个人博客主页.🎉
作者的gitee:https://gitee.com/muxi-c-language.
零基础学习C语言系列:
🎈 https://blog.csdn.net/m0_68931081/category_11742786.html.
🎉小沐和友友们一样喜欢编辑,天天敲代码🤭,沉迷学习,日渐消瘦。很荣幸能向大家分享我的所学,和大家一起进步,成为合格的卷王。✨如果文章有错误,欢迎在评论区✏️指正。那么开始今天的学习吧!😘


在这里插入图片描述

🎈操作符

指令系统的每一条指令都有一个操作符,它表示该指令应进行什么性质的操作。不同的指令用操作符这个字段的不同编码来表示,每一种编码代表一种指令。

其中操作符分为:

  1. 算术操作符
    2.移位操作符
    3.位操作符
    4.赋值操作符
    5.单目操作符
    6.关系操作符
    7.逻辑操作符
    8.条件操作符
    9.逗号表达式
    10.下标引用、函数调用和结构成员

🎈算术操作符

+   -  *(乘)  /(除)   %(取模)

注意:1.✏️除了% 操作符之外,其他的几个操作符可以作用于整数和浮点数

#include<stdio.h>
int main()
{
	int a = 12;
	int x = 5;
	float b = 7.0;
	float c = -6.0;
	float d = b + c;
	float e = b - c;
	float f = b * c;
	float g = b / c;
	int ret = a % x;
	printf("d=%f\ne=%f\nf=%f\ng=%f\nret=%d", d, e, f, g, ret);
	return 0;
}

在这里插入图片描述
2.✏️对于/ 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法

#include<stdio.h>
int main()
{
	int a = 20;
	int b = 10;
	int c = 20.0;
	int d = 10.0;
	int x = a / b;
	float y = c / d;
	printf("x=%d\ny=%f", x, y);
	return 0;
}

在这里插入图片描述
3.✏️% 操作符的两个操作数必须为整数。返回的是整除之后的余数

#include<stdio.h>
int main()
{
	int a = 8;
	int b = 3;
	int c = a % b;
	printf("%d", c);
	return 0;
}

在这里插入图片描述

🎈移位操作符

移位操作符针对的是二进制,所以移动的是二进制,每次运算时,第一步需要转换成对应的二进制,再进行移位。

<< 左移操作符
>> 右移操作符
注:移位操作符的操作数只能是整数。
✨左移操作符

移位规则:

左边抛弃、右边补0

#include<stdio.h>
int main()
{
	int num = 2;
	printf("num<<1=%d", num << 1);
	return 0;
}

在这里插入图片描述

在这里插入图片描述
当num=-2时:

#include<stdio.h>
int main()
{
	int num = -2;
	printf("num<<1=%d", num << 1);
	return 0;
}

在这里插入图片描述
左移一位相当于该数字乘于2,

✨右移操作符

右移操作符相对复杂一点。分为逻辑移位和算术移位。在转换成二进制时,二进制的第一个数字表示正负,即当第一个数字为0时,该数字为正,为1时,该数字为负
例如:
在这里插入图片描述
✏️小知识:整数的二进制表示有三种方式:原码,反码,补码
正整数的原码,反码和补码相同。
负整数的原码,反码和补码不相同。
其中在存储时候,存储的是补码。

在这里插入图片描述

🎉逻辑移位

移位规则:

左边用0填充,右边丢弃

#include<stdio.h>
int main()
{
	int num = -2;
	int a = num >> 1;
	printf("%d", a);
	return 0;
}

在这里插入图片描述

🎉算术移位

移位规则:

左边用原该值的符号位填充,右边丢弃

#include<stdio.h>
int main()
{
	int num = -2;
	int a = num >> 1;
	printf("%d", a);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
小沐用的编译器支持的是算术右移。
警告⚠ :
对于移位运算符,不要移动负数位,这个是标准未定义的。(浮点数也不行)

例如:

int num = 10;
num>>-1;//error

右移一位相当于除与2。

🎈位操作符

位操作符是二进制的运算,故与移位操作符一样,运算的第一步应讲操作数转换成二进制位操作符只适用于整型。
位操作符有:

& //按位与
| //按位或
^ //按位异或

注:他们的操作数必须是整数。

🎉&–按位与

运算规则:有零则为零,同为一才为一。✏️

0&0=0 1&0=0 1&1=0 0&1=0

例如:

#include<stdio.h>
int main()
{
	int a = 3;
	int b = -5;
	int c = a & b;
	printf("%d", c);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

🎉|–按位或

运算规则:有1则为1,同为零才为零。✏️

1|1=1 1|0=1 0|0=1 0|1=1

例如:

#include<stdio.h>
int main()
{
	int a = 3;
	int b = -5;
	int c = a | b;
	printf("%d", c);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

🎉^–按位异或

运算规则:相同为0,不相同为1。✏️

1^0=1 0^1=1 0^0=0 1^1=0

例如:

#include<stdio.h>
int main()
{
	int a = 3;
	int b = -5;
	int c = a ^ b;
	printf("%d", c);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
练习:

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

//代码一
#include<stdio.h>
int main()
{
	int a = 3;
	int b = 5;
	printf("交换前:a=%d,b=%d\n", a, b);
	a = a + b;
	b = a - b;
	a = a - b;
	printf("交换后:a=%d,b=%d\n",a, b);
	return 0;
}

在这里插入图片描述
代码一容易溢出,当a和b都很大时,容易导致a=a+b溢出。
故:

//代码二
#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;
}

在这里插入图片描述
通过:

3^3=0   0^5=5   a^a=0  0^a=a
即3^3^5=0^5=5    3^5^3=5

则按位异或支持交换律。
在这里插入图片描述

🎈赋值操作符

在写代码时候可以通过赋值操作符给变量赋值,从而得到想要的结果。

int weight=120//初始化
weight=90//赋值//注:初始化和赋值不一样
int high=175//初始化
high=185///赋值
//赋值操作符可以连续使用,比如:
int a = 10;
int x = 0;
int y = 20;
a = x = y+1;//连续赋值
//先x=y+1=20+1=21,后a=x=21

//这样的代码感觉怎么样?

//那同样的语义,你看看:
x = y+1;
a = x;
//这样的写法是不是更加清晰爽朗而且易于调试。
✨复合赋值操作符

复合赋值操作符的运算规则和前面的类似。

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

这些运算符都可以写成复合的效果。

int a+=5//a=a+5
int a-=5//a=a-5
int a*=5//a=a*5
int a/=5//a=a/5
int a%=5//a=a%5
int a>>=5//a=a>>5
int a<<=5//a=a<<5
int a&=5//a=a&5
int a|=5//a=a|5
int a^=5//a=a^5

🎈单目操作符

单目操作符只有一个操作数。

✨单目操作符介绍
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
//! 逻辑反操作
#include<stdio.h>
int main()
{
	int flag = 1;
	if (!flag)//flag为假,进入if语句
	{
		printf("是沐曦希呀\n");
	}
	if (flag)//flag为真,进入if语句
	{
		printf("是小沐呀\n");
	}
	return 0;
}

在这里插入图片描述

// -(负值)  +(正值)
//负负得正  正正得正  负正得负
#include<stdio.h>
int main()
{
	int a = -10;
	int b = +a;
	int c = -a;
	printf("b=%d\nc=%d\n", b, c);
	return 0;
}

在这里插入图片描述

//&--取地址操作符
#include<stdio.h>
int main()
{
	int a = 0;
	printf("%p\n", &a);//打印a的地址
	return 0;
}

在这里插入图片描述

//sizeof 操作数的类型长度(以字节为单位)
#include<stdio.h>
int main()
{
	int a = 10;
	int n = sizeof(a);//计算的是a所占的内存的大小,单位是字节
	printf("n=%d\n", n);
	//szieof是一个单目操作符
	//计算的是变量所占内存空间的大小
	int set = sizeof(int);
	//计算类型所创建的变量所占据空间的大小,单位是字节
	printf("set=%d\n", set);
	int sz = sizeof a;//操作符可以省略变量的(),但是类型不能省去
	printf("sz=%d\n", sz);
	return 0;
}

在这里插入图片描述

//~ 对一个数的二进制按位取反//即将0变成1,1变成0
#include<stdio.h>
int main()
{
	int a = 0;
	printf("%d\n", ~a);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

#include<stdio.h>
int main()
{
	int a = 3;
	printf("%d\n", ~a);
	return 0;
}

在这里插入图片描述

//++ 前置、后置++
#include<stdio.h>
int main()
{
	int a = 3;
	int b = ++a;//前置++,先++,后使用//a=a+1,b=a
	int c = a++;//后置++,先使用,后++//c=a,a=a+1
	printf("a=%d,b=%d,c=%d", a, b, c);
	return 0;
}

在这里插入图片描述

//-- 前置、后置--
#include<stdio.h>
int main()
{
	int a = 3;
	int b = --a;//前置--,先--,后使用//a=a-1,b=a
	int c = a--;//后置--,先使用,后--//c=a,a=a-1
	printf("a=%d,b=%d,c=%d", a, b, c);
	return 0;
}

在这里插入图片描述

#include<stdio.h>
int main()
{
	int a = 10;
	printf("%d\n", a--);//后置--
	printf("%d\n", a);
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 0; i < 3; ++i)
	{
		printf("%d ", i);
	}//在for语句中前置和后置无区别,只是前置效率高。
	return 0;
}

在这里插入图片描述

//* 间接访问操作符(解引用操作符)//通常与指针一起使用
#include<stdio.h>
int main()
{
	int a = 10;
	int* p = &a;
	*p = 20;//a=20
	printf("a=%d\n", a);
	printf("*p=%d\n", *p);
	printf("p=%p\n", p);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

//(类型) 强制类型转换//即强制将一种类型转换成另一种类型
#include<stdio.h>
int main()
{
	int a = (int)3.14;
	printf("%d\n", a);
	return 0;
}

在这里插入图片描述

✨sizeof 和 数组

初学C语言时,经常用到sizeof来求数组的大小和元素个数等。
需要区别strlen和sizeof。
sizeof是一个单目操作符,不是一个函数。
strlen是一个库函数,头文件为string.h,是用来求字符串的长度。
例如:

#include<stdio.h>
#include<string.h>
void test1(int arr[])
{
	printf("arr[]=%d\n", sizeof(arr));
}
void test2(char ch[])
{
	printf("ch[]=%d\n", sizeof(ch));
}
int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("arr[10]=%d\n", sizeof(arr));
	printf("ch[10]=%d\n", sizeof(ch));
	test1(arr);
	test2(ch);
	return 0;
}

在这里插入图片描述

注意:1.指针变量不管所指的变量是什么类型,其大小都是4或者8个字节。✏️
当配置是x86时,大小为4个字节;配置为x64时,大小为8个字节。
2.数组作为参数传参时候,传的是数组的首元素的地址。

小知识:

//strcmp是用来比较字符串的内容
//strcpy是用来拷贝内容的
#include<stdio.h>
#include<string.h>
int main()
{
	char arr[10] = { 0 };
	char ch[5] = "abcd";
	strcpy(arr, "母亲节快乐!");
	printf("%d\n", sizeof(ch));
	printf("%d\n", strlen(ch));
	if (~strcmp(ch, "abc"))
	{
		printf("祝小沐的妈妈");
	}
	printf("%s\n", arr);
	return 0;
}

在这里插入图片描述

strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数。
strlen是用来求字符串的长度。

strlen遇到’\0’则停止并返回,只会计算‘\0’之前的元素个数。
sizeof可以求变量(类型)所占空间的大小。

🎈关系操作符

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

这些关系运算符比较简单,但是我们要注意一些运算符使用时候的陷阱。
例如:在编程的过程中把==写成=,导致错误

#include<stdio.h>
int main()
{
	int a = 0;
	if (a = 1)
	{
		printf("hehe\n");
	}
	if (a == 2)
	{
		printf("haha\n");
	}
	return 0;
}

在这里插入图片描述

if("abc"=="abcdef")//这样写是比较两个字符串的首字符的地址
//比较字符串用strcmp

🎈逻辑操作符

逻辑操作符只关注真假,真则返回1,假则返回0。

&& 逻辑与
|| 逻辑或

区分 逻辑与(&&) 和 按位与(&)
区分 逻辑或(||) 和 按位或(|)

#include<stdio.h>
int main()
{
	printf("%d\n", 1 & 2);
	printf("%d\n", 1 && 2);
	printf("%d\n", 1 | 2);
	printf("%d\n", 1 || 2);
	return 0;
}

在这里插入图片描述

//练习1
#include <stdio.h>
int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;//后置++,因为a=0,即为假,故后面的++b和d++不会运行,只运行a=a+1
	printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
	return 0;
}

在这里插入图片描述

//练习2
#include <stdio.h>
int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++||++b||d++;//因为前置++b,b=3,故为真,即运行a++,++b和d++
	printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
	return 0;
}

在这里插入图片描述
&&–左边为假,即为假,则右边就不用计算了。
||–左边为真,即为真,则右边就不用计算了。

🎈条件操作符

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

exp1 ? exp2 : exp3

在这里插入图片描述

//使用条件表达式实现找两个数中较大值。
#include<stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	printf("%d\n", a > b ? a : b);
	return 0;
}

在这里插入图片描述

if (a > 5)
b = 3;
else
b = -3;
//转换成条件表达式
#include<stdio.h>
int main()
{
	int b = 0;
	int a = 0;
	b = (a > 5 ? 3 : -3);
	return 0;
}

🎈逗号表达式

exp1, exp2,exp3...expN

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

//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
//c是多13
//代码2
if (a =b + 1, c=a / 2, d > 0)//if(d>0)
//代码3
a = get_val();
count_val(a);
while (a > 0)
{
//业务处理
     a = get_val();
     count_val(a);
}
//如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a>0)
{
     //业务处理
}

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

✨[ ] 下标引用操作符

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

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	arr[7] = 8;//[]是下标引用操作符(双目操作符:arr和7是操作数)
	7[arr] = 9;//arr[7]-->*(arr+7)-->*(7+arr)-->7[arr]//arr是数组的首元素地址
	//arr+7就是跳过7个元素,指向第8个元素。//*(arr+7)就是第8个元素
	printf("%d\n", arr[7]);
	printf("%d\n", 7[arr]);
	return 0;
}

在这里插入图片描述

✨( ) 函数调用操作符

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

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

在这里插入图片描述

int c=Add(a,b);//()是函数调用操作符,操作数:Add,a,b
//函数调用操作符()的操作数至少有一个,即为函数名
✨访问一个结构的成员
. 结构体.成员名
-> 结构体指针->成员名
#include <stdio.h>
struct Stu
{
	char name[10];
	int age;
	char sex[5];
	double score;
};
void set_age1(struct Stu stu)
{
	stu.age = 18;
}
void set_age2(struct Stu* pStu)
{
	pStu->age = 18;//结构成员访问
}
int main()
{
	struct Stu stu;
	struct Stu* pStu = &stu;//结构成员访问
	stu.age = 20;//结构成员访问
	set_age1(stu);
	pStu->age = 20;//结构成员访问
	set_age2(pStu);
	return 0;
}
#include <string.h>
#include<stdio.h>
struct Stu
{
	char name[20];
	int age;
	double score;
};

void set_stu(struct Stu* ps)
{
	//strcpy((*ps).name, "zhangsan");
	//(*ps).age = 20;
	//(*ps).score = 100.0;

	strcpy(ps->name, "zhangsan");
	ps->age = 20;
	ps->score = 100.0;
}

void print_stu(struct Stu* ps)
{
	printf("%s %d %lf\n", ps->name, ps->age, ps->score);
}

int main()
{
	struct Stu s = { 0 };
	set_stu(&s);
	print_stu(&s);

	return 0;
}

在这里插入图片描述

🎉写在最后

那么今天的学习就到这里了。友友们觉得不错的可以给个关注,点赞或者收藏哦!😘感谢各位友友们的支持。以下的代码希望各位大佬们自行检验哦,毕竟亲手操作让记忆更加深刻。

你的❤️点赞是我创作的动力的源泉
你的✨收藏是我奋斗的方向
你的🙌关注是对我最大的支持
你的✏️评论是我前进的明灯
创作不易,希望大佬你支持一下小沐吧😘

下一期见了!

评论 80
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

沐曦希

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

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

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

打赏作者

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

抵扣说明:

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

余额充值