6.操作符和表达式

目录

算数操作符

移位操作符

位操作符

赋值操作符

单目操作符

关系操作符

逻辑操作符

条件表达式

逗号表达式

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

表达式求值


算数操作符

包括 : +     -     *     %     /

1.他们都是双目操作符,即都有左操作数和右操作数

2.%操作符左右操作数必须是整数,其他的整数和浮点数都可以

3./  操作符 : 若左右操作数都是整数,执行整数除法;左右若有一个浮点数,则执行的是浮点数的计算。

1>

#include <stdio.h>
int main()
{
	int a = 0;
	int b = 0;
	float c = 0;
	scanf("%d %d %f", &a, &b, &c);
	printf("%d %f", a / b, a / c);
	return 0;
}

 2>%不能有浮点数操作数

#include <stdio.h>
int main()
{
	int a = 0;
	int b = 0;
	float c = 0;
	scanf("%d %d %f", &a, &b, &c);
	printf("%d %f", a % b, a % c);
	return 0;
}

 移位操作符

注:不能移动负数位,未定义

>>    右移操作符

<<    左移操作符

1)左移操作符

移位规则:二进制序列向左移动几位,右边补0;将二进制左边的几位去掉,右边在补上相同数量的0;

#include <stdio.h>
int main()
{
	int a = 3; //00000000 00000000 00000000 00000011
			   //一个数在内存中以补码的形式存在,正数的源码,反码,补码都相同;负数的源码按位取反得反码,反码加一得补码
			   //0000000 00000000 00000000 000000110  a<<1 1 * 2^2 + 1 * 2 ^1  = 6
			   //10000000 00000000 00000000 00000011  b 的源码
			   //11111111 11111111 11111111 11111100  b 的反码
	           //11111111 11111111 11111111 11111101  b 的补码
			   //一个数是以源码的形式展现
			   //11111111 11111111 11111111 11111101  b 的补码
			   //11111111 11111111 11111111 11111010  b<<1 的补码
			   //11111111 11111111 11111111 11111001  b<<1 的反码
			   //10000000 00000000 00000000 00000110  b<<1 的源码  -1 (1 * 2 ^ 2 + 1 * 2 ^ 1 ) = -6
	int b = -3;//10000000 00000000 00000000 00000011
	printf("%d %d", a << 1, b << 1);
	return 0;
}

00000000 00000000 00000000 00000011   a的源码
      一个数在内存中以补码的形式存在,正数的源码,反码,补码都相同;负数的源码按位取反得反码,反码加一得补码
0000000 00000000 00000000 000000110  a<<1 1 * 2^2 + 1 * 2 ^1  = 6
10000000 00000000 00000000 00000011  b 的源码
11111111 11111111 11111111 11111100  b 的反码
11111111 11111111 11111111 11111101  b 的补码
      一个数是以源码的形式展现
11111111 11111111 11111111 11111101  b 的补码
11111111 11111111 11111111 11111010  b<<1 的补码
11111111 11111111 11111111 11111001  b<<1 的的补码

10000000 00000000 00000000 00000110  b<<1 的源码  -1 (1 * 2 ^ 2 + 1 * 2 ^ 1 ) = -6

 移位操作在没有赋值时,原值并没有改变

#include <stdio.h>
int main()
{
	int a = 3;
	int b = -3;
	printf("%d %d\n", a << 1, b << 1);
	printf("%d %d\n", a, b);//移位操作在没有赋值时,原值并没有改变
	return 0;
}

 2)右移操作符

移位规则:逻辑移位和算术移位

逻辑移位:去掉右边,左边用0补充

算数移位:去掉右边,左边用符号位补充

#include <stdio.h>
int main()
{
	int a = 3;
	int b = -3;
	//a源码  :  00000000 00000000 00000000 00000011
	//a右移1 :  00000000 00000000 00000000 00000001   a>>1 = 1
	//b源码  : 10000000 00000000 00000000 00000011
	//b反码  : 11111111 11111111 11111111 11111100
	//b补码  : 11111111 11111111 11111111 11111101
	//逻辑移 :
	//          01111111 11111111 11111111 11111110
	//反码 :    01111111 11111111 11111111 11111101        
	//源码       00000000 00000000 00000000 00000010   b = 2
	//算数移:
	// 111111111 11111111 11111111 1111110
	// 111111111 11111111 11111111 1111101
	// 100000000 00000000 00000000 0000010   b = -2 
	printf("%d %d\n", a >> 1, b >> 1);
	return 0;
}

 可知,在vs中,是算数右移

位操作符

&  按位与     有0为0,同1为1

|   按位或     有1为1,同0为0

^  按位异或   相同为0,不同为1

#include <stdio.h>
int main()
{
	int a = 1;//00000000 00000000 00000000 00000001
	int b = 5;//00000000 00000000 00000000 00000101
	printf("%d\n", a & b);//00000000 00000000 00000000 00000001 a&b = 1
	printf("%d\n", a | b);//00000000 00000000 00000000 00000101 a|b = 5
	printf("%d\n", a ^ b);//00000000 00000000 00000000 00000100 a^b = 4
	return 0;
}

#include <stdio.h>
int main()
{
	int a = 3;            //00000000 00000000 00000000 00000011 a 的源码
	int b = -10;          //10000000 00000000 00000000 00001010 b 的源码
	                      //11111111 11111111 11111111 11110101 b 的反码
	                      //11111111 11111111 11111111 11110110 b 的补码
	printf("%d\n", a & b);//00000000 00000000 00000000 00000010  a&b = 2
	printf("%d\n", a | b);//11111111 11111111 11111111 11110111  a|b  的补码
						  //11111111 11111111 11111111 11110110  a|b  的反码
						  //10000000 00000000 00000000 00001001  a|b  的源码  a|b = -9
	printf("%d\n", a ^ b);
	                      //00000000 00000000 00000000 00000011 a 的源码
						  //11111111 11111111 11111111 11110110 b 的补码
						  //11111111 11111111 11111111 11110101 a^b 的补码
						  //11111111 11111111 11111111 11110100 a^b 的反码
						  //10000000 00000000 00000000 00001011 a^b 的源码  a^b = -11
	return 0;
}

 1.不创建变量,完成两个数的交换

#include <stdio.h>
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	printf("a = %d b = %d\n", a, b);
	//一个数^ 它本身 = 0;
	//0 ^ 一个数 = 这个数
	a = a ^ b;
	b = a ^ b;//b = a ^ b = a ^ b ^ b = a ^ 0 = a
	a = a ^ b;//a = a ^ b = a ^ a ^ b = 0 ^ b = b 
	printf("a = %d b = %d\n", a, b);
	return 0;
}

 赋值操作符

复合赋值符:

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

#include <stdio.h>
int main()
{
	int a = 5;
	printf("%d\n", a += 1); //a = a + 1  5+1 = 6
	printf("%d\n", a -= 1); //a = a - 1  6-1 = 5
	printf("%d\n", a *= 1); //a = a * 1  5*1 = 5
	printf("%d\n", a /= 1); //a = a / 1  5/1 = 5
	printf("%d\n", a >>= 1);//a = a >>1  a>>1= 2
	printf("%d\n", a <<= 1);//a = a <<1  a<<1= 4
	printf("%d\n", a %= 1); //a = a % 1  a%1 = 0
	printf("%d\n", a &= 1); //a = a & 1  a&1 = 0
	printf("%d\n", a |= 1); //a = a | 1  a|1 = 1 
	printf("%d\n", a ^= 1); //a = a ^ 1  a^1 = 0
	return 0;
}

单目操作符

!                  逻辑反操作

-                  负值

+                 正值

&                 取地址

sizeof          操作数的类型长度(以字节为单位)

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

--                 前置、后置减减

++               前置、后置加加

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

(类型)          强制类型转换

#include <stdio.h>
int main()
{
	int a = 6;//!0为假,非0为真;
	int b = 0;//!真 = 0; !假 = 1。
	int* pa = &a;
	printf("%d\n", !a);
	printf("%d\n", !b);
	printf("%p\n", pa);
	printf("%p\n", &a);
	printf("%d\n", sizeof(pa));
	printf("%d\n", sizeof(&a));
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(int));
	//printf("%d\n", sizeof int);erro错误
	printf("%d\n", sizeof a);
	printf("%d\n", ~a);
	printf("%d\n", ++a);//前置++,先++后使用;
	printf("%d\n", a++);//后置++,先使用后++
	printf("%d\n", --a);//前置--,先--后使用
	printf("%d\n", a--);//先使用,后--
	printf("%d\n", *pa);
	float d = (float)a;//a的类型是int 前面(float) 把 int 强制转换成 float 类型
	printf("%f\n", d);
	return 0;
}

sizeof 和数组

#include <stdio.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	char arr2[10] = { 'a','b','c','d','e','f','g','h','i','j' };
	printf("%d\n", sizeof(arr1));
	printf("%d\n", sizeof(arr2));
	printf("%p\n", arr1);//数组名表示首元素的地址
	printf("%p\n", arr1 + 1);//数组名+1 表示跳过一个元素的地址
	printf("%p\n", &arr1);
	printf("%p\n", &arr1 + 1);//取地址数组名+1,跳过整个数组
	printf("%p\n", &arr1[0]);//第一个元素的地址
	printf("%p\n", &arr1[0] + 1);//跳过一个元素的地址
	return 0;
}

关系操作符

>      大于

>=    大于等于 

<      小于

<=    小于等于  

!=      不等于

==     等于

#include <stdio.h>
int main()
{
	int a = 0;
	scanf("%d", &a);
	if (a > 0)
		printf("大于0\n");
	if (a < 0)
		printf("小于0\n");
	if (a >= 0)
		printf("大于等于0\n");
	if (a <= 0)
		printf("小于等于0\n");
	if (a==0)
		printf("等于0\n");
	if(a != 0)
		printf("不等于0\n");
	return 0;
}

 

 逻辑操作符

&&     逻辑与;同时满足时为真;只要左边有一个假,就不进行计算

||        逻辑或;只要满足一个就为真;只要左边有一个正,就不进行计算

#include <stdio.h>
int main()
{
	int i = 0;
	int a = 0;
	int b = 2;
	int c = 3;
	int d = 4;
	i = a++ && ++b && d++;//a++是先使用,后++;a为0,为假,则bd不算
	printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);//a 1; b 2;c 3;d 4
	return 0;
}

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

 

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

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

 

#include <stdio.h>
int main()
{
	int a = 0;
	scanf("%d", &a);
	if (a > 0 && a <= 18)
		printf("未成年\n");
	if (a < 0 || a>18)
		printf("成年\n");
	return 0;
}

 

#include <stdio.h>
int main()
{
	int a = 0;
	while ((scanf("%d", &a)) != EOF)
	{
		if (a > 0 && a <= 18)
			printf("未成年\n");
		if (a < 0 || a>18)
			printf("成年\n");
	}
	return 0;
}

 条件表达式

格式:表达式1? 表达式2 : 表达式3(三目操作符)

#include <stdio.h>
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	printf("%d\n", a > b ? a : b);
	return 0;
}

 逗号表达式

逗号表达式,就是用逗号隔开的表达式;逗号表达式的结果,就是最后一个表达式的结果;

格式: 表达式1,表达式2,表达式3,......,表达式n

#include <stdio.h>
int main()
{
	int a = 0;
	int b = 3;
	int c = 4;
	int d = (a = a + 3, b = b + a, c + b);
	printf("%d", d);
	return 0;
}

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

下标引用操作符: []    

函数调用操作符: ()

结构成员操作符: * 或 ->

下标应用操作符:

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for (int i = 0; i < 10; i += 2)
	{
		printf("arr[%d] = %d\n", i, arr[i]);
	}
	return 0;
}

 函数调用:

#include <stdio.h>
void menu()//定义菜单函数
{
	printf("***********************\n");
	printf("***********************\n");
	printf("***********************\n");
	printf("***********************\n");
}
int Add(int x, int y)//定义加法函数
{
	return x + y;
}
int my_strlen(char *s)//定义字符串函数
{
	if (*s == '\0')
	{
		return 0;
	}
	else
		return 1 + my_strlen(s + 1);
}
int main()
{
	int a = 0;
	int b = 0;
	char arr[20] = { 0 };
	scanf("%s", arr);
	menu();//调用打印菜单函数
	printf("输入两个数:>");
	scanf("%d %d", &a, &b);
	printf("%d\n", Add(a, b));//打印加法函数的结果
	printf("%d\n", my_strlen(arr));//打印求字符串函数的结果
	return 0;
}

结构成员操作符:

#include <stdio.h>
struct stu
{
	char name[10];
	int age;
	char sex[10];
	double score;
};
int main()
{
	struct stu s = { "zhangsan",20,"male",90.0 };
	printf("%s %d %s %.2lf\n", s.name, s.age, s.sex, s.score);//结构体变量.结构体成员
	struct stu* ps = &s;
	printf("%s %d %s %.2lf\n", (*ps).name, (*ps).age, (*ps).sex, (*ps).score);//*ps == s
	printf("%s %d %s %.2lf\n", ps->name, ps->age, ps->sex, ps->score);//结构体指针.结构体成员
	return 0;
}

表达式求值

表达式求值的顺序一部分是由操作符的优先级和结合性决定的;有些表达式的操作数在求值时会发生类型转换。

隐式类型转换:c的整型运算至少以整型的精度来进行。

为了获得精度,char 和  short 类型 在运算之前被转换成整型类型,称为整型提升。(整型提升时,高位补充符号位)

1)char的整型提升:

#include <stdio.h>
int main()
{
	char a = 5;
	char b = 126;
	char c = a + b;
	//char a 00000101
	//char b 01111110
	//a和b在计算时,发生了整型提升(计算时,是以补码计算的)
	//a :00000000 00000000 00000000 00000101
	//b :00000000 00000000 00000000 01111110
	//c :00000000 00000000 00000000 10000011  
	//对外显示时,显示的是源码
	//c :10000011(在char中存储)
	//c :11111111 11111111 11111111 10000011 -补码
	//c :11111111 11111111 11111111 10000010 -反码
	//c :10000000 00000000 00000000 01111101 -源码
	//c = -1(2^6 + 2^5 + 2^4 + 2^3 +2^2 + 2^0)=-(1 + 4 +8 +16 +32 + 64) = -125
	printf("%d", c);
	return 0;
}

2)short的整型提升 

#include <stdio.h>
int main()
{
	short a = 32766;
	short b = 5;
	short c = a + b;
	//a :01111111 11111110
	//b :00000000 00000101
	//a,b在计算时,发生了整型提升
	//a :00000000 00000000 01111111 11111110
	//b :00000000 00000000 00000000 00000101
	//c :00000000 00000000 10000000 00000011 
	//c :10000000 00000011(以short类型存储)
	//c :11111111 11111111 10000000 00000011 -补码
	//c :11111111 11111111 10000000 00000010 -反码
	//c :10000000 00000000 01111111 11111101 -源码 = -32765
	printf("%d\n", c);
	return 0;
}

3)short 和 int 混合的

#include <stdio.h>
int main()
{
	char b = 5;
	short a = 32766;
	short c = a + b;
	char d = a + b;
	//a :01111111 11111110
	//b :00000101
	//计算时,发生整型提升
	//a :00000000 00000000 01111111 11111110
	//b :00000000 00000000 00000000 00000101
	//c :00000000 00000000 10000000 00000011
	//d :00000000 00000000 10000000 00000011
	//c和d的存储 
	//c :10000000 00000011
	//d :00000011
	//c和d的对外展示
	//c :11111111 11111111 10000000 00000011 -补码
	//d :00000000 00000000 00000000 00000011 -d = 3
	//c :11111111 11111111 10000000 00000010 -反码
	//c :10000000 00000000 01111111 11111101 -源码 = -32765
	printf("%d\n", c);
	printf("%d\n", d);
	return 0;
}

 

4)

#include <stdio.h>
int main()
{
	char a = 0xb6;
	//10110110  182
	//11111111 11111111 11111111 10110110
	//11111111 11111111 11111111 10110101
	//10000000 00000000 00000000 01001010  -74
	short b = 0xb600;//10110110 00000000 //-18944
	//10110110 00000000 46592
	//11111111 11111111 10110110 00000000
	//11111111 11111111 10110101 11111111
	//10000000 00000000 01001010 00000000 -18944
	int c = 0xb6000000;//10110110000000000000000000000000 =-1241513984
	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)
		printf("c");
	//a,b需要整型提升,提升后为负数(补充符号位(最高位)),与原来的数不相等,所以不打印a和b
	//c不需要整型提升,所以相等。
	return 0;
}

 

#include <stdio.h>
int main()
{
	char c = 1;
	short a = 2;
	printf("%u\n", sizeof(c));//sizeof内部的表达式不进行真实计算
	printf("%u\n", sizeof(+c));
	printf("%u\n", sizeof(-c));
	printf("%u\n", sizeof(a));
	printf("%u\n", sizeof(+a));
	printf("%u\n", sizeof(-a));
	return 0;
}

#include <stdio.h>
int main()
{
	int a = 3;
	char b = 1;
	printf("%d\n", sizeof(b = a + 4));
	printf("%d\n", sizeof(+b));
	return 0;
}

 

 算数转换:操作符的各个操作数属于不同的类型,其中一个转换另一个类型,否则无法进行

寻常算数转换
long double和double,float,unsigned long int,long int,unsigned int,int算数时,其他转换成long double

double

和float,unsigned long int,long int,unsigned int,int算数时,其他转换成double
float和unsigned long int,long int,unsigned int,int算数时,其他转换成float
unsigned long int和long int,unsigned int,int算数时,其他转换成unsigned long int
long int和unsigned int,int算数时,其他转换成long int
unsigned int和int算数时,其他转换成int
int
#include <stdio.h>
int main()
{
	int a = 5;
	float f = 5.5;
	float e = a + f;//表达式有两个属性,值属性,类型属性,5是值属性,int是类型属性
	printf("%f", e);//int发生了算数转换
	return 0;
}

操作符的属性:

操作符的优先级

操作符的结合性

是否控制求值顺序

操作符描述用法示例结果类型结合性是否控制求值顺序
()聚组(表达式)与表达式同N/A
()函数调用rexp(rexp,...,rexp)rexpL-R
[ ]下标引用rexp[rexp]lexpL-R
.访问结构成员lexp.member_namelexpL-R
->访问结构指针成员lexp->member_namelexpL-R
++后缀自增lexp++rexpL-R
--后缀自减lexp--rexpL-R
!逻辑反!rexprexpR-L
~按位取反~rexprexpR-L
+单目,表示正值+ rexprexpR-L
-单目,表示负值-rexprexpR-L
++前缀自增++rexprexpR-L
--前缀自减--rexprexpR-L
*间接访问*rexplexpR-L
&取地址&lexprexpR-L
sizeof取其长度,以字节表示sizeof rexp sizeof(类型)rexpR-L
(类型)类型转换(类型)rexprexpR-L
*乘法rexp * rexprexpL-R
/除法rexp / rexprexpL-R
%整数取余rexp % rexprexpL-R
+加法rexp + rexprexpL-R
-减法rexp - rexprexpL-R
<<左移位rexp << rexprexpL-R
>>右移位rexp >> rexprexpL-R
>大于rexp > rexprexpL-R
>=大于等于rexp >= rexprexpL-R
<小于rexp < rexprexpL-R
<=小于等于rexp <= rexprexpL-R
==等于rexp == rexprexpL-R
!=不等于rexp != rexprexpL-R
&位与rexp & rexprexpL-R
^位异或rexp ^ rexprexpL-R
|位或rexp | rexprexpL-R
&&逻辑与rexp && rexprexpL-R
||逻辑或rexp || rexprexpL-R
 ? :条件操作符rexp? rexp : rexprexpN/A
=赋值lexp = rexprexpR-L
+=以...加lexp += rexprexpR-L
-=以...减lexp -= rexprexpR-L
*=以...乘lexp *= rexprexpR-L
/=以...除lexp /= rexprexpR-L
%=以...取模lexp %= rexprexpR-L
<<=以...左移lexp <<= rexprexpR-L
>>=以...右移lexp >>= rexprexpR-L
&=以...与lexp &= rexprexpR-L
^=以...异或lexp ^= rexprexpR-L
|=以...或lexp |= rexprexpR-L
,逗号rexp, rexprexpL-R

错误代码:

#include <stdio.h>
int main()
{
	int a = 1;
	int b = 2;
	int c = 3;
	int d = 4;
	int e = 5;
	int f = 6;
	int g = a * b + c * d + e * f;//*优先级比+高,只能保证*比+在前,无法保证第三个乘法在第一个加法之前
	a + --c;//只能保证--在+之前,但无法保证c是自减之前还是自减之后的
	b = b-- - --b * (b = -3) * b++ + ++b;//不同编译器结果不同
	int i = (++c) + (++c) + (++c);//不同编译器结果不同
	return 0;
}
#include <stdio.h>
int f()
{
	static int count = 1;
	return ++count;
}
int main()
{
	int a = f() + f() * f();//只能保证乘法在加法之前,无法保证函数调用的顺序
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值