一.万恶的逗号表达式(逗号表达式所'要的是'最后一个值)
首先笔者对于要的是做了一个引号,😂,因为我自己无数次在这里犯错,我十分清楚逗号表达式对于所在表达式是只要最后一个值,但是往往会忘记前面的式子也会运算并将结果体现在后面的式子中。可能大家不太理解,我举个例子:
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
}
这些内容是笔者希望分享给大家,让大家一样不再犯错。希望各位能有所收获吧!!🌹