目录
算术操作符
%
取模操作符的两个操作数必须为整数。
返回的是整除之后的余数。
模0或模负数无意义
int main()
{
int a = 7 % 3.0;
return 0;
}
/
两个操作数都为整数,执行整数除法。
而只要有浮点数执行的就是浮点数除法。
#include <stdio.h>
int main()
{
float a = 100 / 24.0;
float b = 100 / 24;
printf("%f %f\n", a,b);
return 0;
}
移位操作符
所谓移位,移的是二进制位
左移<<
规则:
左边抛弃,右边补0
#include <stdio.h>
int main()
{
int a = 0;
int num = 10;
a = num << 1 ;
printf("%d\n", a);
return 0;
}
右移>>
- 逻辑移位
左边用0填充,右边丢弃
- 算术移位
左边用原该值的符号位填充,右边丢弃
整数的二进制表示形式:
原码:直接根据数值写出的二进制序列就是原码
反码:原码符号位不变,其他位按位取反
补码:反码+1
负数存放在内存中,存放的是二进制的补码
正整数三码相同
-1
原码:1000000000000000000000000001
反码:11111111111111111111111111111110
补码:11111111111111111111111111111111
int main()
{
int b = 0;
int a = -1;
b = a >> 1;
printf("%d\n", b);
return 0;
}
结果仍是-1,说明当前右移操作符使用的是算术右移
注意!!!
对于移位运算符不要移动负数位,这个是标准未定义的!
位操作符
位操作符操作数必须为整数
按位,按2进制位
按位与
&
2个都是1才是1,只要有0就是0
00000000000000000000000000000011
00000000000000000000000000000101
结果:
00000000000000000000000000000001
按位或
|
只要有1就是1,同时为0才是0
按位异或
^
相同为0相异为1
一道面试题:
交换2个int变量的值,不使用第三个变量
int main()
{
int a = 3;
int b = 5;
printf("a=%d b=%d\n", a, b);
a = a + b;
b = a - b;
a = a - b;
printf("a=%d b=%d\n", a, b);
return 0;
}
缺点:数值太大可能会溢出 毕竟只有32位
改进:
#include <stdio.h>
int main()
{
int a = 3;
int b = 5;
printf("a = %d b = %d\n", a, b);
a = a^b;
b = a^b;
a = a^b;
printf("a = %d b = %d\n", a, b);
return 0; }
a^a=0
0^a=a
a^b^b=a
b^a^b=a
练习:
求一个整数存储在内存中的二进制中1的个数。
001101
&
000001
=
000001
最后一位为1才是1
int main()
{
int num = 10;
int i = 0;
int count = 0;//计数
for (i = 0; i < 32; i++)
{
if (num & (1<<i))
count++;
}
printf("二进制中1的个数 = %d\n", count);
//10 00000000000000000000000000001010
return 0;
}
单目操作符
sizeof与数组
求变量(类型)所占空间的大小
单位是字节
void test1(int arr[]) //此处arr[]是 int* arr
{
printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
printf("%d\n", sizeof(ch));//(4)
}
int main()
{
int arr[10] = {0};
char ch[10] = {0};
printf("%d\n", sizeof(arr));//(1)
printf("%d\n", sizeof(ch));//(3)
test1(arr);
test2(ch);
return 0;
}
数组传参传的是首地址
指针的大小始终为4/8,与32位或64位平台有关
int main()
{
short s = 5;
int a = 10;
printf("%d\n", sizeof(s = a + 2));
printf("%d\n", s);
return 0;
}
s的值和类型均为发生改变
sizeof括号中的表达式是不参与运算的
sizeof的运算是在编译时就开始计算的了
test.c-->test.exe(可执行文件)
编译-->链接-->运行
~
int main(){ int a = -1; int b = ~a; //10000000000000000000000000000001 原码 //11111111111111111111111111111110 反码 //11111111111111111111111111111111 补码 printf("%d\n", a); printf("%d\n", b); return 0;}
按位取反对内存中的补码进行按位取反
练习:
int main()
{
int a = 13;
//把a的二进制中的第5位置成1
a = a | (1 << 4);
//00000000000000000000000000001101
// |
//00000000000000000000000000010000
// =
//00000000000000000000000000011101
//
//把a的二进制中的第5位置成0
//00000000000000000000000000011101
// &
//11111111111111111111111111101111
// =
//00000000000000000000000000001101
//00000000000000000000000000010000
a = a & ~(1 << 4);
printf("a=%d\n", a);
return 0;
}
++/--
i++ 先用了再加
++i 先加了再用
int main()
{
int i = 0,a = 0,b = 2,c = 3,d = 4;
i = a++ && ++b && d++;
//i = a++||++b||d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0; }
//程序输出的结果是什么?
1 2 3 4
第一个表达式为0 后面的表达式就不再计算
int main()
{
int i = 0,a = 1,b=2,c = 3,d = 4;
i = a++ && ++b && d++;
//i = a++||++b||d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0; }
//程序输出的结果是什么?
2 3 3 5
int main()
{
int i = 0, a = 1, b = 2, c = 3, d = 4;
//i = a++ && ++b && d++;
i = a++||++b||d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0;
}
//程序输出的结果是什么?
2 2 3 4
1为真,后面的表达式均不用计算
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
//i = a++ && ++b && d++;
i = a++||++b||d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0;
}
//程序输出的结果是什么?
1 3 3 4
逗号表达式
逗号表达式,从左向右依次执行。
整个表达式的结果是最后一个表达式的结果。
a = get_val();
count_val(a);
while (a > 0)
{
//业务处理
a = get_val();
count_val(a);
}
如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a>0) {
//业务处理
}
下标引用,函数调用,结构成员
1.[]下标引用操作符
arr[9]
[]的2个操作数为arr和9
2.()
函数调用必须有函数调用操作符
有时还需要传参
#include <stdio.h>
void test1()
{
printf("hehe\n");
}
void test2(const char *str)
{
printf("%s\n", str);
}
int main()
{
test1(); //操作数为test1
test2("hello bit."); //操作数为test2,"hello bit."
return 0;
}
3.结构成员访问操作符
.
结构体变量.成员名
struct Book
{
char name[20];
char id[20];
int price;
};
int main()
{
struct Book b = { "c语言","c20201311",55 };
printf("书名:%s\n", b.name);
printf("书号:%s\n", b.id);
printf("书价:%d\n", b.price);
return 0;
}
->
struct Book
{
char name[20];
char id[20];
int price;
};
int main()
{
struct Book b = { "c语言","c20201311",55 };
struct Book* pb = &b;
printf("书名:%s\n", pb->name);
printf("书号:%s\n", pb->id);
printf("书价:%d\n", pb->price);
return 0;
}
整型提升
有些表达式的操作数在求值的过程中可能需要转换为其他类型.
C的整型算术运算总是至少以缺省整型类型的精度来进行的.
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型.
整型提升意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度
一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。
通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。
所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,
然后才能送入CPU去执行运算。
int main()
{
char a = 3;
//00000011
//高位补充符号位 0
//00000000000000000000000000000011
char b = 127;
//01111111
//00000000000000000000000001111111
//a和b都是char类型,都没有达到int大小,会发生整型提升
char c = a + b;
//00000000000000000000000010000010
//10000010 -c
//整型提升:
//11111111111111111111111110000010 -补码
//11111111111111111111111110000001 -反码
//10000000000000000000000001111110 -原码
//补码+1=反码 ~反码=原码
//在内存中以补码形式存储,计算
//打印出来的是原码的形式
printf("%d\n", c);//-126
return 0;
}
无符号整形提升,高位补0
正数/负数整型提升,高位补符号位
int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if (a == 0xb6)
printf("a");
if (b == 0xb600)
printf("b");
if (c == 0xb6000000)
printf("c");
return 0;
}
//a,b会进行整型提升,就不是原来的值了
只会输出c
int main()
{
char c = 1;
printf("%u\n", sizeof(c));
printf("%u\n", sizeof(+c));
printf("%u\n", sizeof(-c));
return 0;
}
输出结果 1 4 4
+c -c 进行运算时整形提升了
char,short类型参与运算都会整形提升
比int大的就不用整形提升
sizeof括号内确实不参与运算,但整形提升看的是如果运算过后的结果
算术转换
向空间更大的,精度更高的去转换
long double
double
float
unsigned long int
long int
unsigned int
int
操作符属性
影响表达式求值的因素
- 操作符的优先级
- 操作符的结合性
- 是否控制求值顺序。
+的结合顺序L->R从左到右结合
&&会控制求值顺序 如最左边表达式已经为0,后面的表达式就不会再计算了
||
?:条件操作符
,逗号表达式
均会控制求值顺序
是否任何一个表达式就能计算出一个结果呢?
a*b + c*d + e*f
//计算的时候,由于*比+的优先级高,只能保证的计算是比+早,但是
//优先级并不能决定第三个*比第一个+早执行
a*b
c*d
ab + cd
e*f
ab + cd + e*f
或者:
a*b
c*d
e*f
ab + cd
ab + cd + e*f
int main()
{
int i = 10;
i = i-- - --i * ( i = -3 ) * i++ + ++i;
printf("i = %d\n", i);
return 0; }
int fun()
{
static int count = 1;
return ++count; }
int main()
{
int answer;
answer = fun() - fun() * fun();
printf( "%d\n", answer);//输出多少?
return 0; }
int main()
{
int i = 1;
int ret = (++i) + (++i) + (++i);
printf("%d\n", ret);
printf("%d\n", i);
return 0;
}
以上均为垃圾代码,不同平台结果不一样