c语言 总结操作符使用 理解二进制存储

12月19日随笔

计算机中的补码

在计算机中如果只用原码来做加法,就会运算错误见下例,因此引入补码机制。

1 + (-10000000..0001        //1
1000000..0001        //-1
1000000..0010        //-2 ,计算结果错误

引入补码后

0000000..0001
1111111..1111
0000000..0000     //0   带符号位一起运算,很方便

在c语言中移位运算符默认的是 算术移位 ,即右移补符号位

再看异或,根据两个性质可以做很多文章,就比如不借助变量交换数,求数组出现一次数个数。

a ^a = 0 a^0 = a

#include <stdio.h>
int main(){
    int a[5] = {1,3,6,1,6};
    int size = sizeof(a)/sizeof(a[0]);

    int i = 0;
    int ret = a[0];
    for(i=1; i<size; i++){

        ret = a[i] ^ ret;
        printf("%d\n",ret);
    }
    printf("%d",ret);
}

求一个数字以二进制存储方式中有多少位数字是1

第一种方法是 模2,除2,这种方法对于负数就gg了

第二种方法 循环右移(32次),之后按位与1,就可以计数了

第三种方法 见下

int num = -1;
int i =0;
int count= 0;
while(num){
  count++;
  num = num &(num -1);       //这个表达式可以总是去掉二进制位里的最后一个1
}

上述代码比第二种方法要高效,因为它不需要知道循环次数,总是从最右边的1开始处理。怎么理解呢,减一是不是把最后一位1变0了,然后再和本身与,就能得到去1的效果.

&取数组地址


printf("%p",arr)         //数组首元素地址
printf("%d",arr+1)       //数组第二个元素的地址
printf("%p",&arr)        //数组的地址!!!
printf("%p",&arr +1)     //把整个数组的地址跳过了

sizeof

char a;
sizeof(a);    //1     1个字节
sizeof(&a);    //8    打印的是指向char的指针,64位机指针8字节

char c[10] ;
sizeof(c);    //10    数组名代表整个数组,而不是首元素地址。
sizeof(&c);    //8   

sizeof 内部表达式不参与运算,因为sizeof在编译的时候就进行处理了。

short int a = 0;
sizeof(a = 1 +2 );
printf("%d",a);    //0

~按位取反的妙用

求把指定二进制位置数0/1

//例,要置第3位为0
000000000101
111111111011        //和这个数字相与,可以保证其他位不变,第三位置0,但是这个数怎么的到呢
000000000100         //由这个数按位取反就可以了,这个数好得到呀,1<<3位就好了

而置第n位为反,只需要和指定序列异或运算就可以了。

&&的一个重要特征,前者为0,则不继续运算当前逻辑与表达式

int i =0 ,a = 0, b = 2,c =3,d =4;
i = a++ && ++b && d++;
//a = 1 ,b =2,d =4;

同样的||前者为1,则不继续运算当前逻辑或表达式。

练习1.写一个函数返回参数二进制中 1 的个数

#include <stdio.h>

int count_one(int key){
    int count = 0;
    while(key){
        count ++;
        key = key&(key - 1);
    }
    return count;
}

int main(){
    int key = 0;
    int ret = -1;
    scanf("%d",&key);
    ret = count_one(key);
    printf("%d",ret);
} 

2.获取一个数二进制序列中所有的偶数位和奇数位,分别输出二进制序列。

#include <stdio.h>
int main(){
    int key = 0;
    int count = 1;
    int i =0;
    int que[35]={0};               //这里一定一定要初始化,因为后面不会全部覆盖初值,造成不确定因素 

    scanf("%d",&key);   
    //每次右移一位,取最低位存数组里 
    while(key){
        que[32-count] = key&1; 
        count++;
        printf("count = %d key&1 =%d\n",count,key&1);  //测试 
        key = key>>1;                       
    }
    printf("\n二进制序列\n");
    for(i=0;i<32;i++){
        printf("%d ",que[i]);
    }
    printf("\n偶数位\n"); 
    for(i=0;i<32;i+=2){
        printf("%d ",que[i]);
    }
    printf("\n奇数位\n"); 
    for(i=1;i<32;i+=2){
        printf("%d ",que[i]);
    }
}

这里写图片描述
3.输出一个整数的每一位

#include <stdio.h>
int main(){
    int key = 789;
    while(key){
        printf("%d\n",key%10);        //模10除10 
        key/=10;
    }
} 

4.两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?

#include <stdio.h>
int count_one(int key){
    int count = 0;
    while(key){
        count ++;
        key = key&(key - 1);
    }
    return count;
}
int main(){

    int key1 = 1999,key2 =2299;  
    int tmp = key1 ^ key2;        //不同的位 置1 
    int ret = 0;

    ret = count_one(tmp);        //利用前面写过的计算1函数 
    printf("%d",ret);
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值