C语言操作符总结:

引言:此文章对于C语言中的操作符进行总结说明,易错点分析,配合代码实例,希望读者能对操作符有更深层次的理解。当然其中还有一些二进制处理操作符,库函数,文章中不做过多说明,只对于操作符进行解读。

1.算数操作符:+ - * / %,

解读:其中+-*没有什么考点,对于/有两个考点:1.整数除法  2.小数除法

比如下面代码:可以放到编译器中运行,观察每个变量的结果。这点较为简单,尝试过之后便可以得到结论,所以不过多赘述。

float a = 3 / 5;
float b = 3.0 / 5;
float c = 3 / 5.0;
float d = 3 * 1.0 / 5;
float e = 3 / 5 * 1.0;

对于%需要知道两点:1.a % b,a,b都得是整数  2.范围是[0 ,b-1](控制范围,如生成一个范围内的随机数)这里提供一个随机数生成函数:需要引用time.h和stdlib.h,因为使用了srand和time函数,具体使用不做描述。

int Gen_rand_num(int min,int max)
{
    srand(time(0));
    int num;
    //生成一个min-max之间的随机数:核心要领是明白,取模留下的是谁
    num = rand() % (max-min+1)+min;
    return num;
}

2. 移位操作符:<< 左移位 、>> 右移位。

解读:移位操作只对于整数操作。整数在内存中以补码的形式存放,左移位也是对其补码进行操作,具体操作是:补码整个向左移动,去掉首位,末尾补0。那么有什么作用呢?对这个数翻倍(符号不变)移动一位翻一倍(对于边界条件有待讨论,比如移动32位,移动31位)。右移位有两种:1.算术右移,2.逻辑右移,其中逻辑右移就是右边舍弃,左边补0。而算术右移是根据原来数的符号位进行补充,就是做到不改变原来二进制的符号位。

3.按位与/或/异或:&  |  ^

解读:这里的操作是对于二进制位进行操作:其遵循的原则都是将两个整数的二进制的补码进行比较,得到一个新的整数的补码:1.按位与:两个都为1,才为1,其余为0。2.按位或:有一个为1,就是1。3.按位异或:对应位置的数不相同,则为1,相同为0。其中按位异或与前两者不同:不会进位,所以数值比较相近,其具有很多性质:1.0^a=a,a^a=0  2.a^b=b^a  3.(a^b)^c=a^(b^c) 

应用:1.可以实现不用创建第三个变量达到交换两个整数的目的(按位异或)。 2.编程统计一个整数的二进制中1的个数。(提示:按位与(a&1)和右移位)

4.赋值操作符:= 

解读:将等号右边的值赋给左边。 = 与上述的算数运算符合操作运算符相结合,可以构成符合运算符。需要注意的是, = 两边的表达式是有要求的,左边为左值,右边为右值;左值就是变量,也就是可以修改的值,而右值就是常量,或者称为不可以修改的值,比如int x=5;5是一个常量,x是一个变量,符合=对于数值的要求,而当你改成5=x时,那么编译器就会报错:error C2106: “=”: 左操作数必须为左值,这就是告诉你左边的值为一个不可修改的值,常见的有宏定义常量,const常量,已定义的数组名(数组地址)等。

5.单目运算符:!(逻辑反操作)、-(负值)、&(取地址)、sizeof 、--、++、*(间接访问)、~(按位取反)、(类型)(强制类型转换)。

需要注意的操作符:

1.sizeof,它可以求 1.变量大小  2.某类型数据(比如int)的大小,返回值为int,单位为字节。

2.按位取反:对于一个整数的补码进行按位取反,得到一个新的整数的补码。可以和按位操作结合,达到修改一个整数补码的目的,可以直接操作补码的任意一位改成0/1。

3.前置++和后置++,先使用还是先++,会有不同的结果。

前置:先使用后++,后置先++再使用。例如如下代码:

int add(int x,int y)
{
	return x + y;
}
int main()
{
	int a = 0,b = 1, c = 2;
	printf("a=%d,b=%d,c=%d\n", a++,++b, --c); 
	//结果:a=0,b=2,c=1
//分析:因为a是后置,b,c都是前置,所以a先使用再自增1,对于b先自增再使用,c同理
	printf("a=%d,b=%d,c=%d\n", a, b, c); 
	//结果:a=1,b=2,c=1
	a = 1, b = 1;
//在函数调用的时候,也是要分清楚先使用还是先自增。
	int d = add(a++, ++b);
	printf("d=%d",d);
	//结果:d=3
	return 0;
}

6.关系运算符:> < = ==

解读:其中需要注意的就是==是用来判断两个值是否相等的,这个值可能是数值,比如3==5就是用来判断3是否等于5,而"abd"=="abcde"是在比较两个字符串地址(首字符地址)是否相同,有些相等不能胡乱比较,可能达不到目的。注意:这些关系运算后结果为0/1是一个常量,1代表真,0代表假。比如如下代码:

int a = 1 > 3;
int b = 1 <= 2;
printf("a=%d,b=%d", a, b);
//结果:a=0,b=1

7.逻辑操作符:|| && 逻辑或/与

解读:用来连接常量表达式或者常量。注意:逻辑操作符号是从左向右进行计算判断,比如说对于c=a&&b++,如果a=0,那么b不会++,因为是&&连接,无论b是否为真,那么c的结果都是0了,但是对与a||b++,如果a为真(非0),那么b也将不会计算(又称短路现象)

//360面试题:
	int a=0, b=1, c=2, i;
	i = a++ && b++ && ++c;
	//i=a++||b++||++c;
	printf("a=%d b=%d c=%d d=%d\n", a, b, c, i);
	//结果:a=1 b=1 c=2 d=0
/*结果分析:由于a先使用,所以对于 a++ && b++ 这个部分,无论b怎么样,该表达式的值一定为假,所以对于b不会再做计算,因为这个部分的值为0,所以相当于 0&&++c ,同样c无论怎样,该语句为假,所以c也不会计算*/

上面对于&&的语句进行了分析,对于||也是同理 

8.三目操作符(条件操作符):[(表达式 1)?(表达式 2):(表达式 3)]  

解读:如果表达式1为真,那么整个表达式的值为表达式2的值,否则为表达式3的值。例如下面代码:

    int a = 2, b = 3;
    int max = a < b ? a < b : b++;
    printf("%d", max);
     //结果:1

9.逗号表达式:(表达式 1,表达式 2,表达式 3,…,表达式 N)

解读:逗号表达式的意思是:从左向右依次执行 表达式 1至N,最后一个表达式的值为整个表达式的值。比如如下代码:输出结果为2

int a = 0, b = 1, c = 2;
if (a++, b--, c < 0)
{
	c++;
}
 printf("%d", c);

10.数组下标引用操作符:[ ]

解读:在数组中该操作符相当于*( ),例如如下代码:输出之后都可以修改arr[0]的值。通过*( )就可以理解,arr[1]可以理解为*(arr+1),也就是数组首元素地址+1,再解引用就对数组中第二个元素解引用,这时候对于arr[1]赋值就相当于对*(arr+1)进行赋值。所以下面的代码1[arr]也就容易理解了,相当于是对*(1+arr)赋值,也就是一样的效果。

int arr[5] = {1,2,3,4,5};
arr[1] = 315;
printf("%d\n",arr[0]);
1[arr] = 723;
printf("%d", arr[0]);

11.结构体访问成员操作符: . 和 -> 

解读: . 的应用:常用语结构体变量(非结构体指针变量),比如如下结构体:

struct student            
{
	char name[20];
	int card;
	char flag;
};
int main()
{
	struct student stu1;   //stu1是结构体普通变量
	stu1.card = 20230315;  //对card变量进行赋值
	return 0;
}

-> 的应用:常用于结构体指针变量,比如如下代码:

int main()
{
	struct student stu1;
	struct student* p = &stu1; //定义结构体指针变量存放stu1的地址
	p->card =20230723; //通过箭头解应用访问内部成员
	return 0;
}

对于结构体的指针变量,还有另一种访问方式:(*p).card=20230723;可以达到相同的效果,意思是先对p解应用,*p就相当于是stu1,然后再加.访问其内部成员;需要注意的是,这种写法需要将*p整体括号,因为.的优先级比->更高。

最后需要注意的是,这两种访问相当于替换了该结构体中的变量名,比如p->card=20230723,相当于对该结构体中 card=20230723 进行操作,不难发现,对于int ,double这些数值型变量这样访问没有任何问题,但是对于数组访问往往就会出现问题,比如下面代码:

int main()
{
	struct student stu1;
	stu1.name = "Lisa";
	struct student* p = &stu1;
	p->name = "lisa";
	return 0;
}

 

可以达到修改name数组的目的吗?显然不行,因为这相当于name=Lisa,数组名代表该数组的首地址,地址怎么能赋成字符串呢?况且该地址还是固定的。

所以在vs2022中会出现如下错误:  error C2106: “=”: 左操作数必须为左值;所谓左值就是可以修改的值,比如在程序中定义的变量,int a=6;意思就是将6赋值给a;详细说明参考上面所提到的赋值操作符。那么代码应该如何更改呢?第一种:加上[ ] 此时相当于name[ ],一个个进行赋值即可;第二种:char *strcpy(char *dest, const char *src);利用strcpy函数

       注:在传递函数参数的时候,往往传递指针,因为更加的节省空间。

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

解读:对于该符号来讲,了解即可,可以判断是否是函数,比如abs():整数绝对值函数,又如memcpy(),你可以判断知道这是一个函数,在不知道时候可以查阅资料。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值