C语言操作符总结

算术操作符

+ - * / %

这里要注意 / 操作符运算时如果两个操作数都为整数,执行整数运算,如果其中有一个操作符是浮点数,则计算出来的结果是浮点数。
% 运算两个数必须都为整数,返回余数
移位操作符

移位运算符分为左移操作符和右移操作符
<< 左移操作符
左移指的是逻辑移位(一个数在内存中是以补码形式存储的)
进行左移时,左边抛弃,右边补0;
C语言操作符总结
>> 右移操作符
右移包含逻辑移位和算术移位
逻辑移位(如果是正整数的话进行逻辑移位),移位时左边补0,右边抛弃
算术移位(针对负数才进行算术移位),移位时左边补最高符号位,右边抛弃
C语言操作符总结
位操作符
& //按位与
| //按位或
^ //按位异或
注:他们的操作数必须是整数。
按位与 &
只有对应的两个二进位都为1时,结果位才为1。
按位或 |
只要对应的两个二进位有一个为1时,结果位就为1。
按位异或 ^
相异为1,相同为0。

#include <stdio.h> 
int main() 
{    
	int num1 = 1;    //01
	int num2 = 2;    //10
	num1 & num2;     //00      结果为0
	num1 | num2;     //11      结果为3
	num1 ^ num2;     //11      结果为3
	return 0; 
}

一道变态的面试题:不允许创建第三个中间变量交换两个变量的值

#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",a,b);
	return 0;
}

求一个整数存储在二进制中1的个数

//方法一
#include<stdio.h>
int main()
{
	int num = 10;
	int count = 0;
	while (num)
	{
		if (num % 2 == 1)
		{
			count++;
		}
		num /= 2;
	}
	printf("%d",count);
	return 0;
}
//方法二
int main()
{
	//-1的原码1000000000000001取反后(除符号位之外)是1111111111111110,再+1即1111111111111111
	//C里面数是以补码方式来储存的
	int num = -1;  
	int count = 0;
	int i = 0;
	for (i = 0; i < 32; i++)
	{
		if ((num >> i) & 1 == 1)      //让这个数num的每一位和1按位与,
		{                             //如果结果是1就说明这一位是1,count++计数
			count++;
		}
	}
	printf("二进制中1的个数是:%d\n",count);
	system("pause");
	return 0;
}
//方法三
int main()
{
	int num = -1;
	int count = 0;
	int i = 0;
	while (num)
	{
		count++;
		num &= (num - 1);       //让num和num-1按位与&,比如说10的二进制1010按位与&9的二进制1001,计数1次,
		                        //但是上面刚开始已经计数了一次,所以一共计数了2次,10的二进制里有两个1
	}
	printf("二进制中1的个数是:%d\n", count);
	system("pause");
	return 0;
}

赋值操作符

= 
复合赋值符
+= 
-=
*= 
/=
%= 
>>= 
<<=
&= 
|=
^=

单目操作符

!           逻辑反操作 
-           负值 
+           正值 
&           取地址 
sizeof      操作数的类型长度(以字节为单位) 
~           对一个数的二进制按位取反 
--          前置、后置\--
++          前置、后置\++ 
前置:先自增自减后运算
后置:先运算后自增自减
*           间接访问操作符(解引用操作符) 
(类型)       强制类型转

关系操作符

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

逻辑操作符

&&          逻辑与 
||          逻辑或

 1&2----->0     按位与       01 & 10     结果为0
 1&&2---->1     逻辑与       真 && 真    结果为真
 
 1|2----->3     按位或        01 | 10    结果为3
 1||2---->1     逻辑或        真 || 真   结果为真

360笔试题:(逻辑与和逻辑或的特点)

#include<stdio.h>
int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;
	//i = a++ || ++b || d++;
	printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);
	system("pause");
	return 0;
}

条件操作符

    exp1 ? exp2 : exp3
    如果满足exp1就取exp2否则取exp3

逗号表达式

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

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

下标引用
[ ]
数组名+索引值
函数调用操作符 
( )
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
访问一个结构的成员
.
结构体.成员名
->
结构体指针->成员名
#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;
 }

表达式求值
表达式求值的顺序一部分是由操作符的优先级和结合性决定。
同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。
1、隐式类型转换
C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升
整型提升的意义
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int 的字节长度,同时也是CPU的通用寄存器的长度。 因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。 通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这 种字节相加指令)。
所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
整形提升:看当前变量自身的类型(short、char参与运算均提升,有符号数(负数)无符号数(正数))

实例
char a,b,c;
a=b+c;

b和c的值被提升为普通整型,然后再执行加法运算。
加法运算完成之后,结果将被截断,然后再存储于a中。

如何进行整型提升呢?
正数(无符号)的整型提升:

char c2 = 1; 
变量c2的二进制位(补码)中只有8个比特位:
00000001 
因为 char为有符号的 char 
所以整形提升的时候,高位补充符号位,
即为0 提升之后的结果是: 
00000000000000000000000000000001
无符号整形提升,高位补0

负数(有符号)的整形提升:

char c1 = -1; 
变量c1的二进制位(补码)中只有8个比特位:
1111111 
因为 char 为有符号的 char 
所以整形提升的时候,高位补充符号位,
即为1 提升之后的结果是: 
11111111111111111111111111111111

整形提升的例子1:

#include<stdio.h>
int main()
{
	char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;         //程序执行后只打印C
	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)
		printf("c");
	return 0;
}

a,b要进行整形提升,但是c不需要整形提升,a,b整形提升之后,变成了负数,所以表达式 a==0xb6 , b==0xb600 的结果是假,但是c不发生整形提升,则表达式 c==0xb6000000 的结果是真,最后只打印C。

整型提升的例子2:

int main() 
{
    char c = 1;
    printf("%u\n", sizeof(c));
    printf("%u\n", sizeof(+c));
    printf("%u\n", sizeof(!c));    
    return 0; 

c只要参与表达式运算,就会发生整形提升,表达式 +c ,就会发生提升,所以 sizeof(+c) 是4个字节。表达式 -c 也会发生整形提升,所以 sizeof(-c) 是4个字节,但是 sizeof(!c) ,就是1个字节。
2、算术转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另一个操作数的类型,否则操作 就无法进行。下面的层次体系称为寻常算术转换:

 long double 
 double
 float 
 unsigned long int 
 long int 
 unsigned int 
 int

如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。
警告: 但是算术转换要合理,要不然会有一些潜在的问题。

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

操作符的属性
(空)