~ 按位取反操作符
对二进制序列进行取反 复制代码
如:
int main() { int a = 1; int b = 0; b = ~a; printf("%d\n",b); //-2 } //a : 00000000 00000000 00000000 00000001 ~a: 11111111 11111111 11111111 11111110 -补码 符号位为1,负数 要转化为原码,%d打印的是原码 对补码求补码就是原码 11111111 11111111 11111111 11111110 -补码 10000000 00000000 00000000 00000001 -反码符号位不变其他位按位取反 10000000 00000000 00000000 00000010 - 反码+1 ->值为-2 复制代码
6.程序题:如何把二进制序列某一位为0的翻转1
或运算:某一位或上0,对应的位不翻转。
某一位或上1,如果该位为1,不翻转。如果为0,翻转
方法:使某一位二进制数翻转为1,就或上其他为0,只有对应该位的二进制为1的数
//使0的某一位翻转 int main() { int a = 0; int n = 0; scanf("%d",&n); //第几位翻转 int b = a | (1 << (n-1)); printf("%d对应二进制序列第%d位翻转的结果为%d\n",a,n,b); return 0; } 复制代码
想要第n个二进制位变成1 只需要 按位或(|)上 1<
7,程序题,如何把二进制序列某一位为1的翻转0
方法: 1左移n-1位的数按位取反 再与上该数即可
int main() { int a = 15; //0000 1111 //使第三(第n)位翻转为0 a &= ~(1<<2); printf("%d\n",a);//11 0000 1011 return 0; } 复制代码
以8bit为例子
1左移0位:0000 0001
1左移1位:0000 0010
int main() { int a =13; //0000 1101 a |=(1<<1); //相当于 a = a|(1<<1) 即使a二进制序列第二位翻转为1 printf("%d\n",a);//0000 1111 -15 //恢复 a &=(~(1<<1)); //a = a&(~(1<<1)) 即使a的二进制序列第二位翻转为0 printf("%d\n",a);//0000 1101 -13 return 0; } 复制代码
&& || 逻辑与 逻辑或
C语言中0表示假,非0表示真
&&发生短路现象:
A&&B&&C 当A,B,C同时为真时,结果才为真 A,B,C中有一个为假(0)了,就终止后序计算 复制代码
int main() { int a =0; int b = 1; int c = 1; int d = a++ && b++ && c++; printf("%d %d %d %d\n",a,b,c,d);//1 1 1 0 //原因:a++为后置++,先使用a的值,为0,直接终止运算,然后a的值变成1,后续的i表达式不执行 return 0; } 复制代码
||发生短路现象:
A || B || C A,B,C只要有一个为真,结果就为真 A,B,C中有一个为真(非0为真)了,就终止后序计算 复制代码
int main() { int a = 0; int b = 1; int c = 1; int d = a++ || b++ || c++; printf("%d %d %d %d\n", a, b, c, d);//1 2 1 1 ///原因:a++为后置++,先使用a的值,为0,b++,后置++,先使用b的值,b为1,条件为真,终止后序运算, 然后a++变成1,b++变成2 return 0; } 复制代码
唯一的三目操作符 ? :
P? A:B ; 如果P为真,执行A,否则执行B 如:C= A > B? A:B; ->求两个数的最大值 如果A>B为真。C = A,否则C = B 复制代码
逗号表达式
逗号表达式的结果为最后一个式子
int main() { int a = 1; int b = 3; int c = 0; // c =a++, b++, a + 1; //printf("%d %d %d\n",a,b, c); // 2 4 1 并不是2 4 3 //原因:赋值表达式= 优先级比逗号表达式高,所以相当于c=a++,然后再执行后面的表达式 //正解 c = (a++, b++, a + 1); printf("%d %d %d\n",a,b, c); //2 4 3 return 0; } 复制代码
a = get_val(); count_vao(a); while(a>0) { //处理 a = get_val; count_val(a); } 复制代码
--->上面的表达式也可以用逗号表达式
while(a = get_val(),count_val(a),a > 0) { //处理 } 复制代码
[] 操作符
int main() { int arr[] = {1,2,3,4,5}; int i = 0; for(i = 0;i < 5;i ++) { printf("%p----%p\n",&arr[i],arr+i); } return 0; } 复制代码
数组名是首元素地址,所以 arr+i: 下标为i的元素的地址
arr[4] :[]是操作符,arr和4是它的两个操作数 arr[4] == *(arr+4) 加法支持交换律 -> *(4+arr) ->4[arr] arr[4] 和*(arr+4)对于 所以*(4+arr) -->对于4[arr] 复制代码
再一次说明[]是操作符 arr和4是操作数而已
():函数调用操作符
如:
strlen() 函数:返回的是无符号整形
// /0 不算进字符串长度 printf("%d\n",strlen("abc"));//3 printf("%u\n",strlen("abc"));//3 复制代码
对于函数调用操作符 ()
接收一个或者多个操作数,第一个操作数是函数名,剩余的操作数就是传递给函数的参数
如: my_Add(a,b) ()有3个操作数为 my_Add (函数名) a , b
结构体成员访问操作符 -> .
创建结构体类型本身不占用内存空间,创建结构体变量时才开辟空间
struct Stu { int age; //结构体成员 char name[20]; //结构体成员 }s1,s2; struct Stu s3; //struct Stu是结构体类型 // s1,s2为结构体全局变量 // s3为结构体局部变量 复制代码
struct Stu { int age; char name[20]; }; int main() { struct Stu s[3] = { {20,"zhangsan"} ,{30,"lemon"} ,{10,"shuai"} }; int i = 0; //方法1:结构体变量用.访问 for (i = 0; i < 3; i++) { printf("%d %s\n", s[i].age, s[i].name); } //方法2:结构体指针用->访问 struct Stu* p = &s[0]; printf("%d %s\n", p->age,p->name); //方法3:解引用结构体访问 printf("%d %s\n", (*p).age, (*p).name); return 0; } 复制代码
注意事项:
不可以直接把字符串放进结构体里面的数组中。要使用strcpy函数
#include<string.h> int main() { struct Stu { int age; char name[20]; }; struct Stu s; s.age = 10; //s.name = "mango"; //err,name是数组名,是常量地址,应该把要改的字符串放到name指向的空间里 //正解 -字符串拷贝函数strcpy() strcpy(s.name, "数据结构"); printf("%d %s\n", s.age, s.name); } 复制代码
总结: 结构成员访问操作符 方法1: 结构体变量.成员名 方法2: 结构体指针->成员名 方法3: (*结构体指针).成员名 复制代码
6.整形提升
当计算的两个操作数的类型为short或者char,会发生整形提升,提升为int
7.算术转化
大于4个字节的类型变量进行计算,发生的是算术变化,往高字节的类型转化,最后的结果类型为参加计算的变量类型中字节最大的。
例如:
int a = 0; float b = 0.0f; //C语言的小数默认是double类型,如果想为float类型,就在初始值后面加f double c = 0.0; d = a+b+c; 问:d是什么类型? -》往高字节转化,最后结果为字节数最大的类型 字节:double 8byte int 4 byte float 4byte 所以d为double类型 复制代码