C语言操作符

操作符详解

 


 

算术操作符

 +                 -                 *                 %

  1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
  2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法
  3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。(很重要)!

 移位操作符

<< 左移操作符

>> 右移操作符

左移操作

右移操作:

    逻辑右移

    算术右移

 对于移位运算符,不要移动负数位,这个是标准未定义的。 例如:

int num = 10;

num>>-1;     //error

位操作符

&        //按位与

|         //按位或

       //按位异或

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

方法一

#include<stdlib.h>
#include <stdio.h> 
int main(){
	int num = 10;
	int count = 0;
	while (num){
		if (num % 2 == 1) {
			count++;
		}
		num = num / 2;
	}
	printf("二进制中1的个数 = %d\n", count);
	system("pause");
	return 0;
}

这种方法有一个问题就是不能求负数中1的个数

方法二

#include<stdlib.h>
#include <stdio.h> 
int main(){
	int num = -1;
	int i = 0;
	int count = 0;
	for (int i = 0; i < 32;i++){
		if (((num>>i)&1)==1){
			count++;
		}
	}
	printf("%d",count);
	system("pause");
	return 0;
}

这种方法就比较通用,但过程比较繁琐

方法三

#include<stdlib.h>
#include <stdio.h> 
int main(){
	int num = -1;
	int i = 0;
	int count = 0;
	while (num){
		count++;
		num = num&(num - 1);
	}
	printf("%d",count);
	system("pause");
	return 0;
}

这种方法很好但是不容易想到,所以我们选择自己喜欢的方法解决问题

赋值操作符:=

       复合赋值符:

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

int x = 10;

x = x+10;

x += 10          //复合赋值

单目操作符

 

!                                 逻辑反操作

-                                 负值

+                                正值

&                                取地址

sizeof                        操作数的类型长度

~                                对二进制按位取反(以字节为单位) 

--                                前置,后置--

++                              前置,后置++

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

(类型)                         强制类型转化

sizeof和数组

 

#include <stdio.h> 
#include<stdlib.h>
void test1(int arr[])
{
	printf("%d\n", sizeof(arr));//(1)
}
void test2(char ch[])
{
	printf("%d\n", sizeof(ch));//(2)
}
int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("%d\n", sizeof(arr));//(3)
	printf("%d\n", sizeof(ch));//(4)
	test1(arr);
	test2(ch); 
	system("pause");
	return 0;
}

请大家思考一下1234分别应该输出什么?(极其重要)

前置++/--

//前置++和--
#include<stdlib.h>
#include <stdio.h> 
int main()
{
	int a = 10;
	int x = ++a;
	//先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。x为11。
	int y = --a;
	//先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10;
	printf("%d %d", x, y);
	system("pause");
	return 0;
}

后置++/--

//后置++和--
#include<stdlib.h>
#include <stdio.h> 
int main()
{
	int a = 10;
	int x = a++;
	//先对a先使用,再增加,这样x的值是10;之后a变成11; 
	int y = a--;
	//先对a先使用,再自减,这样y的值是11;之后a变成10;
	printf("%d %d", x, y);
	system("pause");
	return 0;
}

关系操作符

>         >=        <        <=         !=       ==

逻辑操作符

&&          逻辑与

||             逻辑或

条件操作符

exp1 ?     exp2 :    exp3

逗号表达式

exp1, exp2, exp3, …expN

也许大家对这个很陌生我来给大家举个栗子:

#include<stdlib.h>
#include <stdio.h> 
int main()
{
	int a = 1; 
	int b = 2;
	int c = (a>b, a = b + 10, a, b = a + 1); //逗号表达式c是多少?
	printf("%d", c);
	system("pause");
	return 0;
}

答案是输出最后一个表达式的值为:b=2

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

 1.[ ] 下标引用操作符

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

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

[ ]的两个操作数是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.访问结构体成员

. 结构体.成员名

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

#include <stdio.h> 
#include <stdlib.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);
	system("pause");
	return 0;
}

表达式求值

表达式求值的顺序一部分是由操作符的优先级和结合性决定。

同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型

隐式类型转换

C的整型算术运算总是至少以缺省整型类型的精度来进行的。

为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。  

整形提升

//负数的整形提升char c1 = -1;

变量c1的二进制位(补码)中只有8个比特位:

1111111

因为 char 为有符号的 char

所以整形提升的时候,高位补充符号位,即为1 提升之后的结果是:

11111111111111111111111111111111

//正数的整形提升char c2 = 1;

变量c2的二进制位(补码)中只有8个比特位:

00000001

因为 char 为有符号的 char

所以整形提升的时候,高位补充符号位,即为0 提升之后的结果是:

00000000000000000000000000000001

//无符号整形提升,高位补0

#include<stdio.h>
#include<stdlib.h>

int main()
{
	char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;
	if (a == 0xb6){
		printf("a");
	}
	if (b == 0xb600){
		printf("b");
	}
	if (c == 0xb6000000){
		printf("c");
	}
	system("pause");
	return 0;
}

因为char,short int分别为有符号整数,所以char和short在运算的时候高位全部补1,得到的答案为负数,故答案为c

大家一定要记住在C语言中只要字符型和短整型参与运算便会整形提升为int类型

算术转换

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

 

long double

double

float

unsigned long int

long int

unsigned int

int

如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。

float f = 3.14;

int num = f;                     //隐式转换,会有精度丢失

操作符的属性

操作符

描述

用法示例

结果类型

结合性

是否控制求值顺

()

聚组

(表达式)

与表达式

 

N/A

()

函数调用

rexprexp...,rexp

rexp

L-R

[ ]

下标引用

rexp[rexp]

lexp

L-R

.

访问结构成员

lexp.member_name

lexp

L-R

->

访问结构指针成员

rexp->member_name

lexp

L-R

++

后缀自增

lexp ++

rexp

L-R

--

后缀自减

lexp --

rexp

L-R

!

逻辑反

! rexp

rexp

R-L

~

按位取反

~ rexp

rexp

R-L

+

单目,表示正值

+ rexp

rexp

R-L

-

单目,表示负值

- rexp

rexp

R-L

++

前缀自增

++ lexp

rexp

R-L

--

前缀自减

-- lexp

rexp

R-L

*

间接访问

* rexp

lexp

R-L

&

取地址

& lexp

rexp

R-L

 

sizeof

取其长度,以字节表

sizeof rexp sizeof()

 

rexp

 

R-L

(类型)

类型转换

(类型) rexp

 

rexp

 

R-L

*

乘法

rexp * rexp

rexp

L-R

/

除法

rexp / rexp

rexp

L-R

%

整数取余

rexp % rexp

rexp

L-R

+

加法

rexp + rexp

rexp

L-R

-

减法

rexp - rexp

rexp

L-R

<<

左移位

rexp << rexp

rexp

L-R

>>

右移位

rexp >> rexp

rexp

L-R

>

大于

rexp > rexp

rexp

L-R

>=

大于等于

rexp >= rexp

rexp

L-R

操作符

描述

用法示例

结果类型

结合性

是否控制求值顺

<

小于

rexp < rexp

rexp

L-R

<=

小于等于

rexp <= rexp

rexp

L-R

==

等于

rexp == rexp

rexp

L-R

!=

不等于

rexp != rexp

rexp

L-R

&

位与

rexp & rexp

rexp

L-R

^

位异或

rexp ^ rexp

rexp

L-R

|

位或

rexp | rexp

rexp

L-R

&&

逻辑与

rexp && rexp

rexp

L-R

||

逻辑或

rexp || rexp

rexp

L-R

?:

条件操作符

rexp ? rexp : rexp

rexp

N/A

=

赋值

lexp = rexp

rexp

R-L

+=

...

lexp += rexp

rexp

R-L

-=

...

lexp -= rexp

rexp

R-L

*=

...

lexp *= rexp

rexp

R-L

/=

...

lexp /= rexp

rexp

R-L

%=

...取模

lexp %= rexp

rexp

R-L

<<=

...左移

lexp <<= rexp

rexp

R-L

>>=

...右移

lexp >>= rexp

rexp

R-L

&=

...

lexp &= rexp

rexp

R-L

^=

...异或

lexp ^= rexp

rexp

R-L

|=

...

lexp |= rexp

rexp

R-L

逗号

rexprexp

rexp

L-R

这里需要特别注意一些特殊问题:

//表达式的求值部分由操作符的优先级决定。

//表达式1

a*b + c*d + e*f

注释:代码1在计算的时候,由于+优先级高,只能保证的计算是比+早,但是优先级并不能决定第三*比第一个+早执行

所以表达式的计算机顺序就可能是:

a*b

c*d

a*b + c*d e*f

a*b + c*d + e*f

或者:

a*b

c*d

e*f

a*b + c*d

a*b + c*d + e*f

#include <stdio.h> 
int main()
{
	int i = 1;
	int ret = (++i) + (++i) + (++i);
	printf("%d\n", ret);
	printf("%d\n", i); 
	return 0;
}

这个代码中无法确定先执行哪一个括号里面的值。

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值