c语言_Day20_07_21
c语言_Day20_07_211、操作符
1、位操作符
&按位与|按位或 ^按位异或
位操作符的对象为内存中存储的二进制补码
与找假,或找真;异或相同为0,不同为1
int main()
{
int a = 1;
int b = -1;
printf("%d\n", a & b);// 1
printf("%d\n", a | b);// -1
printf("%d\n", a ^ b);// -2
return 0;
}面试题:
[*]不创建临时变量实现两数的交换
思路:1. 加减法(可能会溢出)
2. 异或法
// 加减法
int main()
{
int a = 10;
int b = 20;
a += b;
b = a - b;
a = a - b;
printf("a = %d b = %d\n", a, b);
return 0;
}
// 异或法
int main()
{
int a = 3;
int b = 5;
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
[*]求一个整数存储在内存中的1的个数
思路:按位与。一个位与1进行按位与后,若该位为1则结果与1相同,反之则相反。对32个位遍历,重复进行上述操作,并且每次循环都对1进行左移操作,可判断32个位的1的个数
int main()
{
int num = -1;
int count = 0;
int move = 1;
for (int i = 0; i < 32; i++)
{
if ((num & move) == move)
{
count++;
}
move = move << 1;
}
printf("%d\n", count);return 0;
}2、赋值操作符
赋值操作符可将右值赋予至左值
连续赋值:c语言支持连续赋值,但并不推荐
复合赋值:
+= -==/=%=
\>>=<<=
&= |=^=
左值与右值进行算术操作,得到的结果赋值给左值
3、单目操作符
++ --
! ~
+ -
&
sizeof
(强制类型转换)
只有1个操作数的操作符
!:逻辑取反
&:取地址
*:解引用
sizeof:计算变量或数据类型所占用的内存大小
int main()
{
short s = 0;
int a = 10;
printf("%d\n", sizeof(s = a + 5));
printf("%d\n", s);
return 0;
}sizeof中的表达式不会真实进行计算,故s并未被新赋值
~:按位取反
例:对11进行二进制操作,使其变为15(即二进制第3位由0变为1),再变为11
int main()
{
int a = 11;
a |= (1 << 2);
printf("%d\n", a);
a &= (~(1 << 2));
printf("%d\n", a);
return 0;
}练习:
void test1(int arr[])
{
printf("%d\n", sizeof(arr)); // 4
printf("%d\n", sizeof(arr)); // 4
}
void test2(char ch[])
{
printf("%d\n", sizeof(ch)); // 4
printf("%d\n", sizeof(ch));// 1
}
int main()
{
int arr = { 0 };
char ch = { 0 };
printf("%d\n", sizeof(arr)); // 40
printf("%d\n", sizeof(ch)); // 10
test1(arr);
test2(ch);
return 0;
}test函数接收数组的第一个元素的指针,故其大小在32位系统下为4个字节
4、关系操作符
\> < >=<=!===
5、逻辑操作符
&& ||
短路逻辑:对于逻辑与,若前项为假则不执行后面逻辑;对于逻辑或,若前项为真则不执行后面逻辑
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;// 短路逻辑
printf("%d %d %d %d\n", a, b, c, d);
return 0;
}6、条件操作符
exp1 ? exp2 : exp3
exp1为真,则返回exp2,反之返回exp3
7、逗号表达式
exp1, exp2, exp3...
用逗号隔开的多个表达式,从左向右依次执行,整个表达式结果为最后一个表达式
8、下标引用、函数调用和结构成员
[]
()
. ->
下标引用操作符用于访问数组元素
函数调用操作符用于调用函数
结构成员调用操作符用于调用结构体的成员:
[*]'.'操作符用于调用结构体对象的成员
[*]'->'操作符用于调用结构体对象的指针所指向的成员
struct Car
{
int speed;
char name;
};
int main()
{
struct Car car = { 60, "X1" };
printf("speed = %dname = %s\n", car.speed, car.name);
printf("speed = %dname = %s\n", (&car)->speed, (&car)->name);
return 0;
}2、表达式求值
表达式求值需要注意两部分内容:优先级顺序和类型转换
1、类型转换
[*]隐式类型转换
整形提升:表达式中的字符和短整形操作数在使用之前被转换为普通整形
int main()
{
char a = 3;
char b = 127;
char c = a + b;
printf("%d", c);
return 0;
}
[*]当用a(b)存放3(127)时,a(b)的空间大小为1byte,而3(127)的数据大小为4byte,故数据需要发生截断
[*]字符相加需进行整形提升(按数据类型的符号位进行提升),再计算
[*]将计算结果存放至c中,c的空间大小位1byte,而结果为整形,故数据需要截断
[*]打印整形,故c发生整形提升,得到补码,再转至原码打印
整型提升补充数据规则:
[*]正数补零
[*]负数补一
[*]无符号数补零
文档来源:51CTO技术博客https://blog.51cto.com/u_15285915/3157482
页:
[1]