C语言操作符详解

目录

1.操作符分类

2.算数操作符

3.移位操作符

3.1左移位符

 3.2右移操作符

4.位操作符

5.赋值操作符

6.单目操作符

6.1.!=逻辑反操作符

6.2   -     +

 6.3  & 取地址

​编辑6.4 *解引用操作符

6.5  sizeof操作数的类型长度

sizeof和数组

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

 6.7  ++ --

 7.关系操作符

8.逻辑操作符

 9.条件操作符

10.逗号表达式

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

11.1.[]下标引用操作符

11.2.()函数调用操作符

 11.3.访问一个结构的成员

 12.表达式求值

12.1隐式类型转换

12.2算术转换

12.3操作符属性


1.操作符分类

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

2.算数操作符

+        -        *        /        %

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

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

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

下面举个例子:

那么m、n、k打印的答案是什么呢?

 那么为什么
    int m = 7 / 2;           //因为int是整型打印的也只会是整型
    double n = 7 / 2;     
    double k = 7.0 / 2;

3.移位操作符

<<   左移位符

>>   右移位符

注:移位符的操作数只能是整数

3.1左移位符

移位规则:

左边抛弃,右边补0

移位符移动的是二进制的位

说起移位符号,我们不得不补充一点关于源码、反码、补码的知识了

整数的二进制表示形式有3种,源码、反码、补码 (正数来说源码、反码、补码相等)

原码:按照数值直接写出的二进制序列

反码:对于正数来说,原码=反码、补码

           对于负数来说,反码等于原码符号位 不变,其他位置取反

补码:对于负数来说,补码是反码的二进制+1

 一个整数是4个字节,32位

一个整数写出2进制序列时,就是32位

有符号的整数来说,最高位的1位是符号位

有符号的整数来说,最高位的1是表示负数

有符号的整数来说,最高位的0是表示正数

无符号的整数来说,没有符号位,所有位都是有效位

无符号位例子:unsigned  int num=10;

                         随机数

在计算机中,用补码计算打印出来的是原码

下面我们看一下这个例子:

我们先看一下正数:

int main()
{
	int n = 7 << 1;
	printf("%d", n);
	return 0;
}

 不是源码应该是原码        对不起 这里打错字啦

接下来是 负数:

 

 3.2右移操作符

移位规则:

1.逻辑移位

   左边用0填充,右边丢弃

2.算术移位

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

先举个正数的例子:

 

 接下来看一下负数的:

(算数移位)

 

 (逻辑移位)

 

 当然这样的方法太暴力,不可能实现从-10到+5

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

//例子
int num=-10;
num<<-1;

4.位操作符

&                按位与

|                 按位或

^                按位异或

&遇0得0

| 见1得1

^相同为0,不同为1

练习一下:

  num1& num2

 

 

 一波变态的面试题:

int main()
{
	int a = 10;
	int b = 20;
	a = a ^ b;			
	a = a ^ b;
	a = a ^ b;
	pritnf("%d %d", a, b);
	return 0;
}

5.赋值操作符

赋值操作符简而言之就是得到一个之前不满意的值,你可以重新赋值

int main()
{
    int a=0;  //初始化
    a=10;  //赋值
}

赋值操作符也可以连续使用

int a=10;
int x=0;
int y=20;
a=x=y+1;



a=x=y+1;
={
    x=y+1;
    a=x;
 }

复合赋值符

+=

-=

*=

/=

%=

>>=

<<=

&=

|=

^=

这些操作符可以实现符合效果

例如:

int x=10;
x=x+10;
x+=10;

注意:=是赋值操作符

           ==是判断相等

6.单目操作符

!=

-

+

&

sizeof

~

--

++

*

(类型)

6.1.!=逻辑反操作符

int main()
{
	int flag = 0;
	if (! flag)
		printf("111111111");
	return 0;
}

6.2   -     +

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

 6.3  & 取地址

6.4 *解引用操作符

 对p进行解引用,*p是通过p中存放的地址找到p指向的对象,*p就是a

6.5  sizeof操作数的类型长度

下面看一下这例子:

int main()
{
	int arr[10] = { 0 };
	printf("%d\n", sizeof(arr));
	return 0;
}

这个打印出来将会是什么呢?

 

 为什么是40呢??

因为sizeof(int)=4   arr[40]      4*10=40

我们举个例子在有序数列里面用二分法找一个数

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10};
	int left = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int right = sz - 1;
	int k = 0;
	scanf("%d", &k);
	int flag = 0;
	while (left <= right)
	{
		int mid = (left + right) / 2;

		if (k > arr[mid])
		{
			left = mid + 1;
		}
		else if (k < arr[mid])
		{
			right = mid - 1;
		}
		else
		{
			printf("找到啦,下标是%d\n", mid);
			flag = 1;
			break;
		}
	}
	if (flag == 0)
	{
		printf("没找到");
	}
	return 0;
}

sizeof和数组

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

都会输出什么?

为什么2        4位置会输出 8   8呢

因为我的电脑是64位

如果32位将会输出4

其实int arr[]本质是指针

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

~10为什么会是-11呢?

 6.7  ++ --

 前置++  --        先加一(减一)后使用       ++a

 后置++  --        使用后加一(减一)           a++

前置++  --

后置-- ++

 

 

 7.关系操作符

 >

<

>=

<=

!=

==

注意:==是判断等于

           =是赋值

8.逻辑操作符

&& 逻辑与

||    逻辑或

举个例子:老师让小红和小明来搬书(小明小红一个人完成不了)  1表示来了   0表示没来

小明小红完成否
小明&&小红11完成
小明&&小红10未完成
小明&&小红01未完成
小明&&小红00未完成

举个例子:老师让小红和小明来搬书(小明小红来一个就可以完成)  1表示来了   0表示没来

小明小红完成否
小明||小红11完成
小明||小红10完成
小明||小红01完成
小明||小红00未完成

区分逻辑操作符与和按位与

1&2-------->0

                00000000000000000000000000000001

   &           00000000000000000000000000000010

                00000000000000000000000000000000

1&&2------>1

1真 2真--------->真

区分逻辑操作符或和按位或

1|2---------->3

             00000000000000000000000000000001

|            00000000000000000000000000000010

             00000000000000000000000000000011

1||2

1真 ||2真 --->真

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\n", a, b, c, d);
	printf("%d\n", i);
	return 0;
}

 

 9.条件操作符

exp1?exp2:exp3

int main()
{
	int a = 0;
	int b = 0;
	scanf("%d", &a);
	if (a > 5)
		printf("3");
	else
		printf("-3");
	return 0;
}

这个代码我们要是用条件操作符应该怎么写呢

a>5?3:-3

10.逗号表达式

exp1,exp2,exp3,.........expn

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

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

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

11.1.[]下标引用操作符

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

int arr[10];  //创建数组

arr[9]=10;  //实用下标引用操作符

[]的两个操作数是arr和9

11.2.()函数调用操作符

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

void test1()
{
	printf("111111\n");
}
void test2(const char*str)
{
	printf("%s\n",str);
}
int main()
{
	test1();
	test2("hello hwh");
	return 0;
}

 11.3.访问一个结构的成员

.        结构体.成员名

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

struct Book
{
	char name[20];
	int price;
};
void Print(struct Book* pb)
{
	printf("%s %d\n", (*pb).name, (*pb).price);
	printf("%s %d\n", pb->name, pb->price);
}

int main()
{
	struct Book b = {"C语言", 55};
	printf("%s %d\n", b.name, b.price);

	Print(&b);

	return 0;
}

 12.表达式求值

12.1隐式类型转换

C 的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为 整型 提升
整型提升的意义
表达式的整型运算要在 CPU 的相应运算器件内执行, CPU 内整型运算器 (ALU) 的操作数的字节长度
一般就是 int 的字节长度,同时也是 CPU 的通用寄存器的长度。
因此,即使两个 char 类型的相加,在 CPU 执行时实际上也要先转换为 CPU 内整型操作数的标准长
度。
通用 CPU general-purpose CPU )是难以直接实现两个 8 比特字节直接相加运算(虽然机器指令
中可能有这种字节相加指令)。所以,表达式中各种长度可能小于 int 长度的整型值,都必须先转
换为 int unsigned int ,然后才能送入 CPU 去执行运算。
//实例1
char a,b,c;
...
a=b+c;
b和 c的值被提升为普通类型,然后在执行加法运算。加法运算完成之后,结果被截断,然后在存储到a中。
如何进行整体提升呢?
整型提升是按照变量的数据类型的符号位来提升的

 

 

int main()
{
	char a = 10;
	//00000000000000000000000000001010
	//00001010
	char b = 126;
	//00000000000000000000000001111110
	//01111110
	//00000000000000000000000000001010->a
	//00000000000000000000000001111110->b
	//00000000000000000000000010001000->a+b
	//10001000
	//11111111111111111111111110001000
	//10000000000000000000000001111000 //-120
	char c = a + b;
	printf("%d\n",c);
	return 0;
}

 

12.2算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类
型,否则操作就无法进行。下面的层次体系称为 寻常算术转换

12.3操作符属性

复杂表达式的求值有三个影响的因素。
1. 操作符的优先级
2. 操作符的结合性
3. 是否控制求值顺序
两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。

 

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

对自己好点儿i

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

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

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

打赏作者

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

抵扣说明:

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

余额充值