C语言操作符相关重要性质和问题总结

算数操作符

+       -        *           /         %

1.除法操作符

当两个数都是整数时,执行整数的除法,但有一个数时浮点数时执行浮点数的除法运算。它的应用之一是可以判断一个整数的位数

2.取模操作符

取模操作时两个数必须为整数。它的应用之一是可以判断一个多位数每一位的数字

如求水仙花数中就应用到了求位数和求每一位的大小


移位操作符

该操作符作用于数的补码,功能不再赘述,对于整数而言其补码就时原码,操作后换算易懂。

对于负数而言,其补码等于源码符号为不变其余为按位取反后+1.当操作完成后对于补码-1,然后符号为不变剩余位按位取反得到原码。


>>  右移操作符  一般情况该操作符操作时,可有除二的效果,但是对于-1而言不适用

int main()
{
	int a = -1;
	printf("%d", a>>1);
	system("pause");
	return 0;
}

对于该操作输出结果仍位-1

<<左移操作符  有乘二的效果。

1.算数右移:右侧丢一位,左侧补足符号位

2.逻辑右移:右侧丢弃,左侧补0(两者相异于编译器,但前者更为科学,因此如果一个程序采用了有符号数的右移位操作,它就是不可移植的)

对于移位操作符,不可移动负数位 如n<<-1,    这个标准时未定义的。

位操作符

&    按位(二进制位补码)与(皆1则1,有0则0)            |   按位或 (皆0为0,有1则1)           ^ 按位异或(相同为0相异为1

其中当一个数与1按位与(&)的时候,可以得到该数的最低位 

按位异或的值具有传递性和对称性,一个数和自身异或等于零,反之同零异或等于它本身(出来混总要还得性质,无论多少个数相异或,只要出现与前几位重复的数,值就会一步一步返回若全部重复会归零)

例:若求1,2,3,4,1,2,3,4,5这几个数中求出只出现一次的数字  



最后5轮空,5和0异或结果为5.

它同样可以应用到不借助第三变量的两个数换值

 赋值

赋值表达式的结合性(即求值顺序,每一种操作符的结合性及其他性质在文末表中指出)从右向左:

a=x=y+3相当于a=(x=y+3)也等同于x=y+3;a=x;

虽然大部分情况下两种书写方式赋予的值是一样的,但是后者更易读易懂。然而出现赋值不同的情况是

如果X是个字符变量,那么他们之间会存在隐式转换, 解释详见《C和指针》page 70底部。

单目操作符

! 逻辑取反操作符,其产生的结果位整形0,或者1 可用于if while语句等中的执行

~ 对整形类型的操作数的补码进行求补操作



sizeof操作符,&取地址操作符。

sizeof是判断它操作数的类型长度,字节是它的单位。以下均是正确的表达式

sizeof(int) //int不能去掉括号
sizeof  a;//不建议这样写
sicccczeof(a);
szie(a=b-2);

其中sizeof()括号中可以是表达式,但第四个sizeof表达式中b-2并没有向a赋值,即不参与运算。  

&产生它的操作数的地址,它可以取得变量的地址,从而赋值给指针变量。

※在sizeof求数组长度时

关于数组名,其表示的是首元素的地址

但在一下两种情况表示的是整个数组

sizeof(数组名) 在这里表示的是这里的数组的大小,单位是字节,数组名表示整个数组

&数组名,取出的是整个数组的地址,数组名表示整个数组

&数组名+1是跳过整个的数组的地址,而arr+1是第二个元素的地址

※ 当函数中arr作为首元素地址传入指针,sizeof(arr)计算的是指针的类型长度,所以无论arr是整型还是字符型其在同一个设备上的大小是一样的

~操作符对整型操作数进行求补操作,即操作数1位变成0,0变成1

注意:

int main()
{
 printf("%d",~0);
 reuturn0;
}

该值输出的是-1,因为要以整型格式输出,存储在内存中的二进制数是补码,在求补操作以后,数字变成了负数,要以整型形式输出需要将补码转换为源码。(其中针对于求补的操作数也是在内存中以源码的形式进行求补的)

应用:将二进制数00000000000001010倒数第三位改成1.

可以用按位      000000000000000100得到。得到00000000000001110,但想恢复时可以通过将000000000000000100进行求补操作然后按位得到000000000000001010.

++和--

该操作符分为前置和后者

++a时使用前自增,a++是使用后自增 --同理。

此处增值操作符执行的是对变量值的一份拷贝,这份拷贝应用到了周围表达式如c=a++,这种情况下在进行复制应用到表达式以后增加a的值,++a表示在增加a的值以后复制应用,--同理,所以这是一个值,不能对这个值进行赋值 如 a++=10,这是错误的。

*操作符是间接访问操作符

int main()
{
  int  a=0;
  int *p=&a;//此处*是int*型,用来定义指针变量
  *p  =  5;//此处指间接访问操作符访问p所指向的值

(类型)强制类型转换

将两个不同类型赋值后提示

强制类型转换可以解决问题,但是会导致精度丢失。

关系操作符

关于操作符的易错点,在使用关系操作符,尤其是在应用与if,while语句的判断时,==和=一定要分清,前者是判断后者是赋值,因为c不具备布尔类型所以赋值的情况下任何非零皆为真

逻辑操作符 (控制求值顺序)

&&      ||

&&   若左侧值为假,则不执行右侧表达式

输出结果

因为a++时在使用后增值,对于&&的运算得到的值时0,从而后面的不运算

||      若左值为真,则不执行右侧表达式  ,他们具有短路性质。

但位运算 |  & 操作符两边的操作数都需要进行求值,且逻辑操作的值只有0和1,不同于位运算,所以在执行if while等条件判断时需要仔细

条件操作符;(控制求值顺序)

逗号操作符   (控制求值顺序)

表达式自左向右逐个求值,但整个逗号表达式式的值就是最后的那个表达式的值。一版情况下不建议使用,难分辨易混乱。

下标引用操作符和函数调用

下标应用操作符 []

它有两个操作数,数组名和索引值且它和*间接访问操作符是等价的,但优先级不同,如

arr[数]==*(arr+数);

函数调用操作符至少有一个操作数,那就是函数名

结构成员

 ->  该操作符用于结构成员的访问,用法如下


#include<stdio.h>
#include<Windows.h>
struct poppin //定义结构体类型,名为poppin
{
	int popper;   //定义结构体成员
	char blf[10];
	char sex[6];
};
void test(struct poppin*ps)
{
	strcpy(ps->blf,"KOD");//此处ps等价于(*p).
}
int main()
{
	struct poppin s; //定义结构体变量
	test(&s);
	printf("%s", s.blf);//输出结构体中的成员blf


	system("pause");
	return 0;

}

输出结果


隐式类型转换

将字符型或者短整型进行整型算数求值的时候存在隐式转转换,换句话说当要进行运算时,编译器自动将进行整型提升

int main()
{
  char a=1;
  char b=127;
  char  c= a+b;//这个过程中的隐式转换导致了最终结果的不同
   printf("%d",c);
}

最终的输出结果位 -127。因为a,b,c都是字符型,他们值由一个字节,在进行整型的加法运算时,会将二进制位从八位调整到32位,最后补码相加得到的二进制数的有效数字大于八位,要以整型输出,补齐符号位(符号位为1则全补1),得到源码为-127.

操作符的属性

操作符具有三个属性,结合性,优先级,是否控制求值顺序。

表见《C和指针》page81-82.

优先级决定的是两个相邻操作符,若优先级相同,则按照他们的结合性。除此之外,编译器可以自由决定任何顺序对表达式的求值,只要不为非  ,  &&  ||  ?: 这几个操作符的限制。

如   s=a*b+c*d+e*f  不同的编译器求出的值可能不同。

再者 如  c+--c,  我无法判断左侧的C是在c--执行之前还是执行之后赋值的,所以不同编译器有不同的结果。

  这类表达式都是有歧义的,个人认为一个合格的程序员应该 是严谨和追求高效性,不仅通俗易懂而且具有很高的可读性和一致性才是关键,而不是追求极力简洁和酷炫。


本章总结个人认为是片面和考虑欠妥的,但贴出的实例都予以测试,任何错误之处请指出.








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值