C语言入门(七)之进制、位运算、左移右移

版权声明:如果觉得文章对你有用,转载不需要联系作者,但请注明出处 https://blog.csdn.net/jinxin70/article/details/83239406

十进制、八进制、十六进制的表示和输出

#include <stdio.h>

int main(int argc, const char * argv[])
{
//     1.默认就是10进制
    int num = 12;
//    2.在前面加上一个0就代表八进制
    int num1 = 014;
    
//    %d是以十进制的方式输出一个整数
    printf("%d\n", num1);
//    %o是以八进制的方式输出一个整数
    printf("%o\n", num);
    
//    在数值前面加上0b就代表二进制
    int num2 = 0b1100;
    printf("%d\n", num2);
//    在数值前面加上0x就代表十六进制
    int num3 = 0xc;
    printf("%d\n", num3);
//     %x是以十六进制的方式输出一个整数
    printf("%x\n", num);
    
//     口诀:不看你怎么存,只看你怎去取
    
    return 0;
}

进制转换

#include <stdio.h>

int main(int argc, const char * argv[])
{

    /*
     十进制  -> 二进制
     9
     转换原理:除2取余 倒序读取
     
     
     9/2  4  1
     4/2  2  0
     2/2  1  0
     1/2  0  1
     
     9 --> 1001
     
     
     二进制 --> 十进制
     1001
     转换原理:乘以2的幂数(幂数从0开始), 然后相加
     
     1 * 2(0) = 1
     0 * 2(1) = 0
     0 * 2(2) = 0
     1 * 2(3) = 8
     
     1 + 0 + 0 + 8 = 9
     
    1 1 1  1 1
   16 8 4  2 1

     
     N位二进制的取值范围
     1位  取值范围 0~1  0~2的1次方-1
     2位  取值范围 0~3  0~2的2次方-1
     3位  取值范围 0~7  0~2的3次方-1
     n位  取值范围  0~2(n)-1
     
     000
     001
     010
     011
     100
     101
     110
     111
     
     
     11111 0~ (32-1)
     
     
     二进制转换为八进制  进制越大表示的位数就越短
     规律:三个二进制位代表一个八进制位  
     因为3位的最大取值是7 而八进制是逢八进一
     
     1个字节 8位
     000   0
     001   1
     100   4
     
     014

     
     二进制转换为十六进制
     规律:四个二进制位代表一个十六进制位
     因为4位的最大取值是15, 而十六进制是逢十六进一
     
     0000 0
     1100 c
     
     0xc
     
     */
    printf("%d\n", 0b1001);
    
    return 0;
}

原码、反码、补码

内存中存储的是补码。正数的三码一样,负数的补码等于原码取反加一

#include <stdio.h>

int main(int argc, const char * argv[])
{
//    int占4个字节 1个字节8位
    int num = 12;
    /*
//     12的二进制
     12在内存中存储的是它的补码
     00000000  00000000 00000000 00001100
     正数的特点:(三码合一) 正数的原码就是TA的反码就是TA的补码
     
     
     -12
     二进制的最高位我们称之为符号位 
     如果符号位是0代表是一个正数,
     如果符号位是1代表是一个负数
     
     10000000  00000000 00000000 00001100 (-12的原码)
     11111111  11111111 11111111 11110011(反码, 符号位不变其它位取反)
     
     11111111  11111111 11111111 11110011
    +00000000  00000000 00000000 00000001
     _____________________________________________
     11111111  11111111 11111111 11110100(补码 , 反码+1)
     
     结论:无论正数负数在内存中存储的都是补码
     
     
     
     11111111  11111111 11111111 11110101 (补码)
    -00000000  00000000 00000000 00000001  (-1)
     _____________________________________________
     11111111  11111111 11111111 11110100 (反码)
     10000000  00000000 00000000 00001011
     
     
     */
    printf("%d\n", 0b11111111111111111111111111110101);
    return 0;
}

位运算

位运算都是针对二进制的


& 按位与


特点:只有对应的两位都是1才返回1 否则返回0
口诀: 一假则假
规律:任何数按位与上1结果还是那个数

     1001
    &0101
   _______
     0001
     
     
      1001
     &1111
     ______
      1001

| 按位或


特点:只要对应的两位其中一位是1就返回1
口诀:一真则真

    1001
  | 0101
  ________
    1101

^ 按位异或


特点:对应的两位不相同返回1 相同返回0

     1001
   ^ 0101
    _______
     1100

多个整数按位异或的结果和顺序无关(重要,交换律)

     1001
   ^ 0101
     _______
     1100
     
     1100
   ^ 0110
     _______
     1010
     
     1001
   ^ 0110
     _______
     1111
     
     1111
   ^ 0101
     _______
     1010
     

相同整数按位异或结果是0

     1001
   ^ 1001
     _______
     0000

任何整数按位异或上0结果不变

     1001
   ^ 0000
     _______
     1001

任何整数按位异或上另一个整数两次结果还是那个数

     1001
   ^ 1001
     ____________
     0000
     
     0000
    ^0101
     ______
     0101

练习

//    int result = 9 & 5;
//    int result = 9 | 5;

//    int result = 9 ^ 5;
//     多个整数按位异或的结果和顺序无关
//    int result2 = 9 ^ 5 ^ 6;
//    int result2 = 9 ^ 6 ^ 5;
//    相同整数按位异或结果是0
//    int result3 = 9 ^ 9;
//    任何整数按位异或上0结果不变
//    int result4 = 9 ^ 0 ;
//    任何整数按位异或上另一个整数两次结果还是那个数
//    int result5 = 9 ^ 9 ^ 5;
//    int result6 = 9 ^ 5 ^ 9;
//    printf("result = %d\n", result6);

~ 按位取反


特点: 0变1 1变0

      0000 0000 0000 0000 0000 0000 0000 1001
     ~1111 1111 1111 1111 1111 1111 1111 0110 (补码)
      0000 0000 0000 0000 0000 0000 0000 0001
     ______________________________________________
     1111 1111 1111 1111 1111 1111 1111 0101 (反码)
     1000 0000 0000 0000 0000 0000 0000 1010
        int result = ~9;
        printf("%d\n",0b11111111111111111111111111110110);

<< 左移
 

a << n 把整数a的二进制位往左边移n位

移出的位砍掉,低位补0, 发现左移会把原有的数值变大
9 << 1 = 18  9 * 2(1) = 18
9 << 2 = 36  9 * 2(2) = 26
9 << n =  9 * 2(n)

左移的应用场景:当要计算某个数乘以2的n次方的时候就用左移,效率最高

注意点:左移有可能改变数值的正负性

>> 右移

a >> n 把整数a的二进制位往右边移n位
移出的位砍掉, 缺少的以为最高位是0就补0是1就补1(是在当前操作系统下)
9 >> 1 = 4  9 / 2(1) = 4
9 >> 2 = 2  9 / 2(2) = 2
右移的应用场景:当要计算某个数除以2的N次方的时候就用右移,效率最高
0000 0000 0000 0000 0000 0000 0000 0000
000000 0000 0000 0000 0000 0000 0000 10

位运算练习(重要)

1、将一个整数以二进制方式输出

要求定义一个函数, 传入一个整数, 输出该整数的二进制
     %i %o %x
     
     0000 0000 0000 0000 0000 0000 0000 1001
    &0000 0000 0000 0000 0000 0000 0000 0001
     
     // 1.让9的二进制向右移31, 就可以获取到9得最高位的二进制, 然后让9的二进制的最高位和1相&, 那么就可以获得9的最高位
     // 2.让9的二进制向右移30, 就可以获得9二进制的第二位
     // 3.以此类推, 直到0位置
     
     技巧:
     1.任何数与1相&都是那个数
     2.利用位移取出每一位
void printBinay(int value)
{
    // 1.定义变量需要向右移动的位数
    int offset = 31;
    // 2.通过循环取出每一位
    while (offset >=0) {
        int result  = (value >> offset) & 1;
        printf("%i", result);
        // 3.每次取出一位就让控制右移的变量-1
        offset--;
        if ((offset+1) % 4 == 0) {
            printf(" ");
        }
    }
    printf("\n");
}

2、利用位运算符, 判断一个数的奇偶性

    // 开发中常用的方式
    if (num % 2 == 0) {
        printf("偶数\n");
    }else
    {
        printf("奇数\n");
    }
     1001 9
     1011 11
     
     1010 10
     1100 12
     通过观察, 我们发现如果是偶数, 那么二进制的最后一位是0, 如果是奇数那么二进制的最后一位是1
if ((num & 1))
    {
        printf("奇数\n");
    }else
    {
        printf("偶数\n");
    }

3、交换两个变量的值

    a = a ^ b;
    b = a ^ b; // b = a ^ b ^ b == a
    a = a ^ b; // a = a ^ a ^ b == b

利用异或的性质,可以做加解密

//    用户密码 , 纯数字
    int pwd = 123456789;
//    对用户密码进行简单加密
    int result = pwd ^ 998;
    printf("加密后:%d\n", result);
//    对用户密码进行解密
    result = result ^ 998;
     printf("解密后:%d\n", result);

猜你喜欢

转载自blog.csdn.net/jinxin70/article/details/83239406
今日推荐