算术操作符:
**1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
2.1 左移操作符
使用规则:
左边抛弃,右边补0
2.2 右移操作符
使用规则:
逻辑移位 : 左边用0填充,右边丢弃。
算术移位 : 左边用原该值的符号填充
3.位操作符位操作符有:(这里的位都是二进制位)
这里都是看二进制位喔
& //按位与 0和0还是 0 , 1和0还是0 , 必须两个都为1 才能结合出来1
| //按位或 只要有一个1就能结合出来1啦,而只有;两个0 才能结合出来0
^ //按位异或 相同为0 相异为1
注:他们的操作数必须是整数。
#includeint main()
{int a = 1;
int b = 2;
a & b;
a | b;
a ^ b;
return 0;
}
给大家介绍一个比较神奇的代码,它是不创建变量,然后将a,b内容交换。用的正是这里介绍的按位异或^操作符
#includeint main()
{int a = 10;
int b = 20;
a = a^b; //把a^b 看成一个钥匙,它遇到a就能打开b的然后变成b;
b = a^b;//a相当于钥匙,它遇到b就打开b变成a,然后再赋给b;b就变成a的值了
a = a^b;//b相当于钥匙,它遇到a就打开a变成b,然后再赋值给a,a值就变成了b值
printf("a = %d b = %d\n", a, b);
return 0;
}
编写代码实现: 求一个整数存储在内存中的二进制中1的个数
#includeint main()
{int num = 10;
int count= 0;//计数
while(num)
{if(num%2 == 1)
count++;
num = num/2;//正常思想从如何分解一个数的各个位数,,%10 再/10;
}
printf("二进制中1的个数 = %d\n", count);
return 0;
另一种方法:
#includeint main()
{int num = -1;
int i = 0;
int count = 0;//计数
for(i=0; i<32; i++)
{if( num & (1<< i) )
count++;
}
printf("二进制中1的个数 = %d\n",count);
return 0;
}
还有没有更好的方法呢?
int main()
{int a = -1;
int count = 0;
//怎么更好的计算a的1 的个数呢?
// a & (a - 1);这种方式可以每次把最右边的1给拿掉;
while (a)
{a = a&(a - 1);
count++;
}
printf("1的个数:%d", count);
return 0;
}
但这种方法实在想不到喔…
4.赋值操作符看好是一个 = 而不是两个==喔
int a=10;//可以将想要的数赋值
int b=a+10;
复合赋值符
5.单目操作符+=
-=
*=
/=
%=
<<=
&=
|=
^=
单目操作符介绍
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转
1. sizeof是用来计算变量所占空间的大小 ,它是一个操作符,不是库函数喔。
void test1(int arr[])
{printf("%d\n",sizoeof(arr));
}
void test2(char ch[])
{printf("%d\n",sizeof(ch[]);
}
int main()
{int a = 10;
char s = 'a';
int arr[10] = {0 };
char ch[10] = {0 };
printf("%d\n", sizeof(a)); //一个整形4个字节
printf("%d\n", sizeof(s));//1一个字符1个字节
printf("%d\n", sizeof(arr));//数组10个整形40个字节
printf("%d\n", sizeof(ch));//数组10个字符10个字节
test1(arr);//问题1:这个是多少呢?
test2(ch);//问题2:这个又是多少呢?
return 0;
}
问题1和问题2其实本质一样,这里把arr和ch传给函数test1和test2,函数传参,这里数组传过去的是首元素地址,也就是相当于指针,而sizeof计算地址大小这个就是由编译器是X64还是X32决定的了,如果是64位的那么大小应该是8,如果是32位的大小应该是4.
3 .前置++和后置++
前置++: 先++后使用。
后置++:先使用后++。
int main()
{int a = 10;
int x = ++a;
//前置++,先将a自增变成11,再使用a,将a赋值给x,x=11;
printf("a=%d x=%d\n", a, x);
return 0;
int main()
{int a = 10;
int y = --a;
//前置--,先将a自减成9,再使用a,将a赋值给x ,x=9
printf("a=%d y=%d\n", a, y);
}
int main()
{int a = 10;
int z = a++;
//后置++,先将a赋值给z,z=10,再给a自增+1,a就变成11;
printf("a=%d z=%d\n", a, z);
}
int main()
{int a = 10;
int v = a--;
//后置--,先将a赋值给y,y=10,再给a自建-1,a就变成9了;
printf("a=%d v=%d\n", a, v);
}
6.关系操作符>>=<<=
!=
== 注意和一个=的区别
7.逻辑操作符&& 逻辑与
|| 逻辑或
区别:
逻辑与 -------按位与
逻辑或 -------按位或
1&&2 ---->1(表示真)
1&2 ---->0(二进制进行计算)
1||2 ---->1(表示真)
1|2 ---->3(二进制进行计算)
逻辑与和逻辑或有什么特点呢?
短路求值!
比如逻辑与&&: 表达式1&&表达式2 表达式1为假则右边不再进行。
逻辑或|| : 表达式1||表达式2 表达式1为真则右边不再进行。
int main()
{int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0;
}
因为 i = a++ && ++b && d++; a++是后置++,先使用后++,所以a=0,先使用与&&进行配对,然后是假,
所以后面++b, d++都不再进行,但a++,这个还是进行的,所以a用完后还要给a+1,
所以a=1,b=2,c=3,d=4;
int main()
{int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++||++b||d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0;
}
这里a++(a=0,先使用与||配对为假,再+1,++b,b自增为3与||配对为真,后面的d++不再进行了所以
a=1,b=3,c=3,d=4;
8.条件操作符表达式1 ? 表达式2 :表达式3 表达式1成立--->最终结果为表达式2,否则为表达式3.
一般条件表达式(if else )可以用条件操作符代替
求两个数中较大值:
int main()
{int a = 10;
int b = 20;
int max = (a >b ? a : b);//a表达式1 a>b如果成立那么max=a,否则max = b;
printf("%d", max);
return 0;
}
9.逗号表达式表达式1,表达式2,……表达式n
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一 个表达式的结果
int main()
{int a = 0;
int b = 1;
int c = (a >b, a = b + 10, a, b = a + 1);//逗号表达式
printf("%d", c);
//c是多少?
return 0;
}
虽然结果是最后一个但是前面的逗号表达式还是要进行的,第一个a>b假的,不用管,第二个a=b+10,a=11了,第三个b=a+1,那b就等于12
a = b + 1;
c = a / 2;
if (d >0)
{……
}
写成逗号表达式if (a = b + 1, c = a / 2, d >0)
在这里插入代码片
10.下标引用、函数调用和结构成员1. [ ]下标引用操作符
操作数:一个数组名+一个索引值
int main()
{int arr[5] = {0,1,2,3,4};//创建数组,初始化
printf("%d",arr[4]);//arr[4]是等于4
arr[4]=10; //使用下标引用改变arr[4]成10
[]操作数是arr和 5
return 0;
}
2.( )函数调用操作符
接收一个或多个操作数,第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
void test()
{printf("hello\n");
}
void test1(char * ch)
{printf("%s", ch);
}
int main()
{test();
test1("hello");
return 0;
}
3. . 访问一个结构的成员
. 结构体.成员名
->结构体指针->成员名
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;
}
11.表达式求值表达式求值的顺序一部分是由操作符的优先级和结合性决定。
同样,有些表达式的操作数在求值的过程中可能需要转化成其他类型
11.1.隐式类型转化
C语言算术运算总是至少以缺省型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转化为普通整形,这种转化称为整形提升。
整形提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的 字节长度一般 就是int的字节长度,
同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为 CPU 内整型操作
数的标准长度。通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有
这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才
能送入CPU去执行运算
int main()
{char a, b, c;
a = b + c;//b+c要进行整形提升,b和c的值被提升到普通整形,然后再进行加法运算
//加法运算完成之后,结果将被截断,然后再存贮到a中。
return 0;
}
怎么进行整形提升的呢?
整形提升是按照变量的数据类型的符号位来提升的
负数的整形提升
>int main()
{
char ch = -1;//字符一个字节---8个比特位
变量ch的二进制位(补码)中只有8个比特位;
11111111
因为char为有符号的char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
return 0;
}
正数整形提升
int main()
{
char ch = 1;
//变量ch的二进制位(补码中)只有8个比特位
00000001;
因为char 为有符号的char
所以整形提升的时候,高位补充符号位即为0;
提升之后的结果就是:
00000000000000000000000000000001
无符号整形提升,高位补0;
return 0;
}
整形提升的例子1:
int main()
{char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if (a == 0xb6)
{printf("a");
}
if (b == 0xb600)
{printf("b");
}
if (c = 0xb600000)
{printf("c");
}
return 0;
}
结果是什么呢?
这里是因为a和b都要先进行整形提升,而c不需要进行整形提升。
a,b整形提升之后变成了负数,所以表达式,a==0xb6,b= =0xb600为假,c的结果为正,所以只打印c
实例2:
int main()
{char a = 1;
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(+a));
printf("%d\n", sizeof(-a));
return 0;
}
嘿嘿结果又是多少呢?
神奇嘛?
实例2中的,a只要参与表达式运算的,就会发生整形提升,表达式+a,就会发生整形提升,所以sizeof(+a)就是4个字节。
表达式-a也会发生整形提升,所以sizeof(-a)也是4个字节,但sizeof(a)没有发生整形提升所以是1个字节。
11.2.算术转化
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转化为另一个操作数的类型,否则操作就无法进行,下面的层次体系为寻常算术转化
long double
double
float
unsigned long int
long int
unsigned int
int
如果某个操作数的类型在上面这个列表中排名较低,那么首先要转化为另一个操作数的类型后进行运算
但要注意算术转化要合理,要不然就会存在一些潜在问题
float a=3.14;
int num =a; 在会发生隐式转化,精度丢失
11.3.操作符的属性
复杂的表达式的求值会有三个影响因素:
1.操作符的优先级
2.操作符的结合性
3.是否控制求值顺序。
两个相邻的操作符先执行哪一个?这个取决于他们的优先级,如果两个优先级相同,那再取决与他们的结合性。
操作符优先级:
下面给出详细的操作符的优先级表格,从上至下优先级依次递减(越靠近上面,操作符的优先级越高)
![在这
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
售后响应及时
7×24小时客服热线数据备份
更安全、更高效、更稳定价格公道精准
项目经理精准报价不弄虚作假合作无风险
重合同讲信誉,无效全额退款