一.万恶的逗号表达式(逗号表达式所'要的是'最后一个值)
首先笔者对于要的是做了一个引号,😂,因为我自己无数次在这里犯错,我十分清楚逗号表达式对于所在表达式是只要最后一个值,但是往往会忘记前面的式子也会运算并将结果体现在后面的式子中。可能大家不太理解,我举个例子:
int main() { //+的优先级高于+= int a, b, c; a = 5; c = ++a;//6 b = ++c, c++, ++a, a++;//c=8,a=8,b=7 经典逗号表达式,这里就有坑,首先b=a++,其次这里运算后b应该等于7,前面的++a会使得a变成7,然后由于后面的a++是后置,所以b=7,而注意在后续运算中a=8了 b += a++ + c;//a=9,c=8,b=23,a先以原本值参与计算再在后面的式子以a+1的值参与运算 printf("a=%d,b=%d,c=%d\n", a, b, c);//9,23,8 }
这是比较经典的一道题,也是我摘录过来的。挺有意思的
二.让人迷糊糊的大端小端
大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址 中; 小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地 址中。--每次读到定义我都很迷,就算理解了过两天就有分不清楚了。我按照自己浅薄的理解简要梗概一下。
小端存储是小的一端先存入低地址处,再依次向高地址处存放;"机器"在读取打印时是先打印高地址再打印低地址例如0x11223344 打印由高地址到低地址就是0x11223344,而在调试中是44332211(观者可以尝试)。
笔者简要绘制了一个图形:
存储是 44 33 22 11 地址由低到高,进行更改也是由低到高。某度曾经出过如何检测机器是如何存储的。
这里给出两个方法:
1.常用方法
int main() { int a=0x11223344;//验证是如何存储 char*pc=(char*)&a; *pc=0;//由于强制类型转换只操作char*大小 printf("%x\n",a);//%x代表是16进制 return 0; }
2.联合体方式
int check_sys() { //采用联合体是借助联合体的特性来操作 union { int i; char c; }un; un.i=1; return un.c; } int main() { int ret=check_sys(); if(ret==1) printf("是小端\n"); else printf("是大端\n"); return 0; }
三.i是局部变量的话是随机值,全局变量不初始化默认是0;整形在和无符号数进行比较的时候,整形要转化成无符号数进行计算。
也用😳代码解释吧。
int i; int main() { i--; if (i > sizeof(i))//首先i全局变量默认是0,其次整形在和无符号数进行计算的时候要转换成无符号数参与计算,故-1特别大; { printf(">\n"); } else printf("<\n"); return 0; }
输出为>
四.运算时容易忽略的整形提升
别忘了运算时的整型提升,对于非int型(cpu的通用寄存器长度)进行运算要进行整型提升,非整形数打印整形整型提升不够的位补符号位,
无符号位直接高位补零:
整型提升的例子:
int main() { char a = 0xc6; short b = 0xc600; int c = 0xc6000000; if (a == 0xc6) printf("a"); if (b == 0xc600) printf("b"); if (c == 0xc6000000) printf("c"); return 0;//只能打印出来c,因为a和b分别是char和short类型,所以在运算中会整型提升,发现值不再相等 }
第二大块:操作符的一些编码题目(有时操作符真的很有用,如果观者遇到一些考察"二进制的题目"而百思不得其解不妨想象底层的操作符,🌹)
1.统计二进制中1的个数
方法一:%2 /2 因为是二进制存储,故%2下来只有0和1两种情况。类似于十进制的。不过要注意%的对象只能是整形(笔者栽过坑)
int count_one_bit(unsigned int*get) { int count=0; while(*get) { if(*get%2==1) { count++; } *get=*get/2; } return count; } int main() { int get=0; scanf("%d",&get); int count=count_one_bit((unsigned int*)&get);//转化为unsigned int 的原因是因为如果仅仅整形,负数是无法计算的,故要转换 printf("count=%d\n",count); system("pause");//停一下 return 0; }
2.法二
32个bit位,一个一个扣下来按位与&,右移操作符 按位与&
int count_one_bit(unsigned int*get) { int i=0; int count=0; for(i=0;i<32;i++) { if((*get)>>i&1==1) count++; } return count; } int main() { int get=0; scanf("%d",&get); int count=count_one_bit((unsigned int*)&get); printf("count=%d\n",count); return 0; }
3.法三(最优也是最难以理解)
//实现原理-以一个数字13为例 //1101 n //1100-12 n-1 //n=n&(n-1),按位与后最右边1消失了 ///1100 m --12 //1011(m-1)--11 //m与m-1 按位与后变为1000 //1000 //0111 按位与后变为0000 //n=n&n-1后就会让二进制序列里右边的1消失,执行几次就有几个1 int count_bit_one(unsigned int*get) { while(*get) { *get=*get&(*get-1); count++; } return count; } int main() { int get = 0; scanf("%d", &get); int count = count_bit_one((unsigned int*)&get); printf("count=%d\n", count); return 0; }
使用按位异或 ^
求二进制中不同位的个数
编程实现两个二进制数m和n中,有多少个位(bit)不同
int count_dif_bit(unsigned int*m,unsigned int*n) { //先按位异或得到一个数,在进行求这个数有多少个1,即可解得 int count = 0; unsigned int tmp = (*m) ^ (*n); while(tmp) { //用上文的最优解法 tmp = tmp & (tmp - 1); count++; } return count; } int main() { //避免代码冗余,直接设为无符号数类型 unsigned int m = 0; unsigned int n = 0; scanf("%u%u", &m, &n);//%u是返回无符号数类型 int count= count_dif_bit(&m, &n); printf("count=%d\n", count); return 0; }
打印二进制的奇数位和偶数位
题目内容:获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出来
void Print(int* m) { int i = 0; printf("奇数位:\n"); for (i = 30; i >=0 ; i-=2) { //打印奇数位 printf("%d ", (*m) >> i & 1); } printf("\n"); printf("偶数位:\n"); for (i = 31; i >=1; i -= 2) { //打印偶数位 printf("%d ", (*m) >> i & 1); } printf("\n"); } int main() { int m = 0; scanf("%d", &m); Print(&m); return 0;//1011--00000000 }
这些内容是笔者希望分享给大家,让大家一样不再犯错。希望各位能有所收获吧!!🌹