标准c语言4

进制转换:

现在的CPU只能识别高低两种电流,只能对二进制数据进行计算。

二进制数据虽然可以直接CPU计算识别,但不方便书写、记录,把二进制数据转换成八进制是为了方便记录在文档中。

随着CPU的不断发展位数不断增加,由早期的8位逐渐发展成现在的64位,因此八进制就不能满足需求了,所以发展出了十六进制,但由于历史原因八进制还不能退出历史舞台。为了理解编程时的一些奇怪现象,我们需要掌握二进制数据、八进制数据、十六进制数据。

二进制数据:

由0~1两个数字组成,逢2进1,由于计算机的运算器只能识别高低两种电流,所以它在运算时只能识别二进制数据。

十进制转换成二进制:

假如把x转换成二进制,x/2记录下余数,然后对商继续除以2,重复这个过程,直到商为0结束,然后把记录的余数倒序汇总,就得到了x的二进制。

例如:117转换成二进制
    117 / 2 余数1
    58 / 2 余数0
    29 / 2 余数1
    14 / 2 余数0
    7 / 2 余数1
    3 / 2 余数1
    1 / 2 余数1
    0
    117的二进制就是:01110101
    
手算:79 63 121 49

练习:实现一个函数,能够打印无符号的十进制数据的二进制。

#include <stdio.h>
​
void print_binary(unsigned long num,char result[],size_t len)
{
    int cnt = len-1;
    do{
        result[cnt--] = num % 2;
        num /= 2;
    }while(cnt >= 0);
}
​
int main(int argc,const char* argv[])
{
    unsigned int num;
    printf("请输入一个整数:");
    scanf("%u",&num);
    char result[32];
    print_binary(num,result,32);
​
    for(int i=0; i<32; i++)
    {
        printf("%d",result[i]);
    }
}

八进制数据:

由0~7八个数字组成,逢8进1,早期使用它记录二进制数据,现在基本不再使用,文件的权限还依然使用8进制数据表示,所以还无法退出历史。

二进制数据转换八进制:

三位二进制对应一位八进制。

    000 0
    001 1
    010 2
    011 3
    100 4
    101 5
    110 6
    111 7
   
注意:

在C代码中,以0开头的是八进制数据,以%o输出的也八进制数据。

十六进制数据:

由0~9和a~f十六个字符组成,随着计算机的发展CPU的位数越来越多,输出的二进制也越来越长,随后科学家又发明出十六进制用于记用二进制数据。

二进制转换成十六进制:

四位二进制对应一位十六进制,超过9的用字母ABCDEF表示(不区分大小写)。

    1000 8
    1001 9
    1010 a
    1011 b
    1100 c
    1101 d
    1110 e 
    1111 f 
注意:

在C代码中,以0x开头的是十六进制数据,以%x,%p输出的是十六进制数据。

%#x、%#o 以对应的进制显示数据

任意进制转换成十进制:

每一个非0位带该公式求和 v*b^(n-1) 就得到了十进制。 ​ v 值 ​ b 进制 ​ n 位数

10101100 128+32+8+4 172

0123 64+16+3

关于进制转换可能遇到的笔试题:

1、十进制转换成二进制、八进制、十六进制(以%o或%x为输出占位符)

统一先转换成二进制,然后再把二进制转换成八进制或十六进制。

2、在代码阅读题中遇到0123或0xabcdf

0开头的是8进制,0x开头的是十六进制,可以先转换成二进制再转换10进制,然后再运算。

3、输入一个整数转换成N进制(2<= N <= 35)

#include <stdio.h>
​
int main(int argc,const char* argv[])
{
    int m = 0 , n = 0;
    scanf("%d%d",&m,&n);
    char bits[32] = {} , cnt = 0;
​
    while(m)
    {
        bits[cnt++] = m % n;
        m /= n;
    }
​
    for(int i=cnt-1; i>=0; i--)
    {
        if(bits[i] < 10)
        {
            printf("%d",bits[i]);
        }
        else
        {
            printf("%c",'A'+bits[i]-10);
        }
    }
}
​

原码、反码、补码:
原码:

正数二进制就是它的原码。

负数符号位为1,数值部分取绝对值的二进制就是它原码。- 10

10000000 00000000 00000000 00001010

反码:

正数的原码就是它的反码

负数的反码是他的原码除符号位外,按位取反。

11111111 11111111 11111111 11110101

补码:

正数的原码就是补码

负数的反码+1是补码。

11111111 11111111 11111111 11110110

十进制的数据是以补码形式存储在计算机中的,因为计算机的CPU中只有加法器,也就是只能运算加法,其它运算都是使用加法模拟的。

为了能计算出a-b也就是a + -b 所以需要使用特殊格式存储负数。

1 + (-1)

0000 0001

1111 1111 -1补码

1000 0000 补码

0111 1111 反码

0000 0000 原码

// 以8位计算机为例
24 - 15
24 + -15
10001111 -15的原码
11110000 -15的反码
11110001 -15的补码   
00011000 24的补码
​
00001001 结果是补码,最高位为0,所以是9
    
// 以32位计算机为例
10000000 00000000 00000000 00001111 -15的原码
11111111 11111111 11111111 11110000 -15的反码
11111111 11111111 11111111 11110001 -15的补码  
00000000 00000000 00000000 00011000 24的补码
00000000 00000000 00000000 00001001 结果是9
    
0xfffffff1
    
​

练习:计算出-4567,-1234的补码,把补码转换成16进制赋值给int类型变量,打印输出验证。

-4567   
10000000 00000000 00010001 11010111 原码
11111111 11111111 11101110 00101000 反码
11111111 11111111 11101110 00101001 补码
0xffffee29
    
-1234
10000000 00000000 00000100 11010010 原码
11111111 11111111 11111011 00101101 反码
11111111 11111111 11111011 00101110 补码
0xfffffb2e
    
-127【-128 = -127 + -1】
        11111111 原码
        10000000 反码
        1000 0001 补码 【printf(“%hhd”,0x81)】
        【%hd 00000000 10000001 ->129】
​

补码转换成十进制整数:
补码的两种解析方式:
无符号解析:

由于无符号数据全部是正数,所以补码就是原码,直接转换成十进制即可。

有符号解析:1100011

根据补码的最高位判断它是整数的补码还是负数的补码。

最高位是1:它必然是负数的补码。

1、补码-1得到反码

2、反码符号位不变,按位求反得到原码

3、原码转换成十进制数据。

最高位是0:它必然是正数的补码,直接转换成十进制即可。

int num = 11111111 11111111 11111011 00101110;
1、由于最高位是1,它必须是负数的补码
2、补码-1 得到反码
    11111111 11111111 11111011 00101101
3、反码 按位求反 得到 原码
    10000000 00000000 00000100 11010010
    1024+128+64+16+2 
    -1234

注意:

当遇到补码转换成十进制数据的笔试题时,必须有是否是有符号信息。

// 假如以下变量的补码是10110011,代码会输出什么,补码的符号信息已经包含在代码中了
char num;
printf("%hhd",num);
10110011
10110010
11001101
64+8+4+1   
-77
​
// 把以下补码转换成十进制数据,条件不够充分
11001100
注意:

一个整型变量的取值范围是环型状的,当它是最大值时再加1就会变成最小值,当它是最小值时减1就是变成最大值。

以char类型数据为例:
-128 
10000000 补码
01111111 -1后的补码,转换成十进制的结果是127
    
127
01111111 补码
10000000 加1后的补码,转换成十进制的结果是-128
​
char特殊的补码:
10000000 最小值(最高位是1,其余全是0)
01111111 最大值(最高位是0,其余全是1)
11111111 -1(所有二进制位都是)
// 以下循环执行多少次:
char cnt = 7, n = 0;
while(cnt)
{
   cnt -= 3;
    n++;
}
printf("%hhd\n",n);
​
7    45
-128  1
125   42
-1    42
-127  1
126   42
0     173
    
for(char i = 0;i<128;i++)
    
for(uint8_t i = 10;i >= 0;i--)    

练习:实现一个函数,显示一个整数的补码(num可能是正数也可能是负数)。

#include <stdio.h>
​
void show_bit(int num)
{
    int back = num;
    char bit[32] = {} , i = 0;
    do{
        bit[i++] = num % 2;
        num /= 2;
    }while(num);
​
    if(back < 0)
    {
        char carry = 1;
        for(int i=0; i<32; i++)
        {
            bit[i] = !bit[i];
            bit[i] += carry;
            carry = bit[i] /2;
            bit[i] %= 2;
        }
    }
​
    for(int i=31; i>=0; i--)
    {
        printf("%hhd",bit[i]);
    }
    printf("\n");
}
​
int main(int argc,const char* argv[])
{
    show_bit(0x80000000);
}

位运算符:

位运算符是针对数据的补码进行运算。

A & B 按位与运算,它是针对数据的补码进行按位与运算
    0 & 0 结果是0
    0 & 1 结果是0
    1 & 0 结果是0
    1 & 1 结果是1
    1001 & 0111
    0001
​
A | B 按位或运算
    0 | 0 结果是0
    0 | 1 结果是1
    1 | 0 结果是1
    1 | 1 结果是1
​
A ^ B 按位异或运算
    0 ^ 0 结果是0 
    0 ^ 1 结果是1 
    1 ^ 0 结果是1 
    1 ^ 1 结果是0
​
~A 按位求反,是单目运算符
    ~0 结果是1 
    ~1 结果是0
​
x << n 把x的补码前n位丢掉,末尾补上n个0,按位左移。
    10101100 << 3 01100000
    0000 1000
    
x >> n 把x的补码后n位丢掉,前面n位,如果x是正数则补0,如果是负数则补1。
    char num = -3;
    printf("%hhd\n",num >> 2+1);
    num<<3;
    printf("")

练习:实现一个函数,显示一个整数的补码(num可能是整数也可能是负数)。

#include <stdio.h>
void show_bit(int num)
{      
    for(int i=0; i<32; i++)
    {
        printf("%hhd",((num<<i)&0x80000000)?1:0);
    }
}
int main(int argc,const char* argv[])
{
    show_bit(0x78787878);
}
​
#include <stdio.h>
void show_bit(int num)
{      
    char bit[32], n = 0;
    for(int i=0; i<32; i++)
    {
        bit[n++] = (num>>i) & 1;
    }
    for(int i=31; i>=0; i--)
    {
        printf("%hhd",bit[i]);
    }
}
int main(int argc,const char* argv[])
{
    show_bit(0x77777777);
}
练习2:输入一个整数,把它的4~7位设置1010,其它位置不变。【先与再或】

n & ~(f<<4) | (0xA << 4)

练习3:输入两个整数,把A的4~7位设置为B的3~6位,其它位置不变。

a & ~(0xf0) | (b << 1 & 0xf0)

2048游戏:

1、需要4x4的二维数组。

2、在数组中随机产生4|2,两个数字。

3、显示界面

4、获取方向

5、把数组中的数字向某个方向移动(相同的数字要合并),统计得分。

6、如果数组发生了移动,要在数组再随机产生一个4|2。

7、检查游戏是否结束(没有空位置,上下左右相邻的数字没有相同的),如果不需要结束继续步骤3。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <getch.h>
#include <time.h>
​
unsigned short arr[4][4] = {};
unsigned long score = 0;
​
void init_game(void);
​
void show_arr(void);
​
void up_move(void);
void down_move(void);
void right_move(void);
void left_move(void);
​
void rand_num(void);
​
bool check_over(void);
​
int main(int argc,const char* argv[])
{
    init_game();
​
    for(;;)
    {
        show_arr();
​
        switch(getch())
        {
        case 183: 
            up_move();
            break;
        case 184:
            down_move();
            break;
        case 185:
            right_move();
            break;
        case 186:
            left_move();
            break;
        case 'n':
            init_game();
            break;
        case 'q':
            return 0;
        }
​
        rand_num();
​
        if(check_over())
        {
            show_arr();
            printf("xxxxxxxxxxxxxx\n");
            break;
        }
    }
}
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值