进制转换:
现在的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的二进制就是:000000000000001110101
手算:79 88 121 46
练习1:实现一个函数,能够获取无符号int的十进制数据的二进制
void print_binary(unsigned int num,char result[],int len);
// result 输出型参数 存储数据的二进制结果
#include <stdio.h>
void print_binary(unsigned int num, char result[], int len) {
int cnt = len - 1;
while(cnt >= 0) {
result[cnt--] = num % 2;
num /= 2;
}
}
int main() {
unsigned int num;
printf("请输入一个整数:");
scanf("%u",&num);
char result[32];
print_binary(num,result,32);
for (int i = 0; i < 32; ++i) {
printf("%hhd",result[i]);
}
}
八进制数据:
由0~7八个数字组成,逢8进1,早期使用它记录二进制数据,现在基本不再使用,文件的权限还依然使用8进制数据表示,所以还无法退出历史。0644
二进制数据转换八进制:
从二进制的低位开始划分,每三位二进制对应一位八进制。
000 0
001 1
010 2
011 3
100 4
101 5
110 6
111 7
注意:
在C代码中,以0开头的是八进制数据,以%o输出的也八进制数据。
0644
十六进制数据:
由09和af十六个字符组成,随着计算机的发展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 值 645
b 进制 8
n 位数 5+4 * 8 +6 * 64
课下算:334 6进制数 788 9进制数
关于进制转换可能遇到的笔试题:
1、十进制转换成二进制、八进制、十六进制,先统一转换成二进制,然后再把二进制转换成八进制、十六进制
2、在代码阅读题中遇到类似 0123 或者 0xabcd,数据的开头使用0 或者 0x,那么隐藏了这是个八进制、十六进制数据的含义,需要先转换后运算
3、输入一个整数和一个N,把该整数转换成N进制数 (2<=N<=35)(超过10的位使用字母表示)
#include <stdio.h>
int main() {
int num = 0, N = 0;
scanf("%d %d", &num, &N);
char result[32] = {} ,cnt = 0;
while(num) {
result[cnt++] = num % N;
num /= N;
}
for (int i = cnt - 1; i >= 0; --i) {
if (result[i] < 10) {
printf("%hhd", result[i]);
} else {
printf("%c",'A' + result[i] - 10);
}
}
}
原码、反码、补码:
原码:
正数二进制就是它的原码。
负数符号位为1,数值部分取绝对值的二进制就是它原码。
反码:
正数的原码就是它的反码
负数的反码是他的原码除符号位外,按位取反。
补码:
正数的原码就是补码
负数的反码+1是补码。
十进制的数据是以补码形式存储在计算机中的,因为计算机的CPU中只有加法器,也就是只能运算加法,其它运算都是使用加法模拟的。
为了能计算出a-b也就是a + -b 所以需要使用特殊格式存储负数。
-127
1111 1111 原码
1000 0000 反码
1000 0001 补码 0x81
// 以8位计算机为前提
24 - 15
1000 1111 15原
1111 0000 15反
1111 0001 15补码
0001 1000 24
0000 1001 9补码
注意:同一个数据,以不同类型显示时,可能结果不一样,所以要统一类型去讨论
%hhd 0x81 -127
%d 0x81 129
-1234
-5678
补码转换成十进制整数:
补码的两种解析方式:
无符号解析:
由于无符号数据全部是正数,所以补码就是原码,直接转换成十进制即可。
有符号解析:
根据补码的最高位判断它是正数的补码还是负数的补码。
最高位是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(所有二进制位都是1)
// 简述下列代码的执行过程
char ch = 7, n = 0;
while(ch) {
ch -= 3;
n++;
}
135 %3 45
-128 1
125 % 3 41
2
130 %3 43
-127 1
126 %3 42 0
173 但是char范围是-128-127 结果应该-83
printf("%d\n",n);
for (char i = 0; i < 128; ++i) 死循环
for (uint8_t i = 10; i >= 0; --i) 死循环
位运算符:
位运算符是针对数据的补码进行运算。
A & B 按位与运算,它是针对数据的补码进行按位与运算
0 & 0 结果是0
0 & 1 结果是0
1 & 0 结果是0
1 & 1 结果是1
1001 1101 0x9d
0011 1110 0x3e
0001 1100 0x1c
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,按位左移。相当于乘2
10101100 << 3 01100000
01100000
0000 0001 << 1
0000 1000
x >> n 把x的补码后n位丢掉,前面n位,如果x是正数则补0,如果是负数则补1。
char num = -3;
printf("%hhd\n",num >> 2+1);
1000 0011
1111 1100
1111 1101
1111 1111
实现一个函数,显示一个整数的补码(该整数可能是负数也可能是正数)
#include <stdio.h>
void show_bit(int num) {
char bits[32] = {};
for (int i = 0; i < 32; ++i) {
bits[i] = num >> i & 1;
}
for (int i = 31; i >= 0; --i) {
printf("%hhd", bits[i]);
}
}
int main() {
show_bit(88);
}
输入一个整数,把它的4~7位置为1100,其它位不变
00000000 00000000 00000000 11110000 0xf0
11101101 11110111 11111111 10101000 num
11111111 11111111 11111111 00001111 & ~0xf0
11101101 11110111 11111111 00001000 |
00000000 00000000 00000000 11000000 0xc0
int num;
num & ~0xf0 | 0xc0
num & ~(0xf<<4) | 0xc0 先与再或
标准C语言项目:2048游戏
1、需要4*4的整数二维数组
2、需要在数组的随机空位置产生2|4
3、显示界面
4、获取方向键
5、把数组中的数字向方向键的方向移动(前方数字相同,就要合并,并统计分数)
6、如果数组发生了移动或合并,再在随机空位置产生一个2|4
7、检查游戏是否失败(没有空位置或者不能再合并),如果没有结束重复步骤3往下
#include <stdio.h>
#include <stdbool.h>
int arr[4][4] = {};
// 随机位置产生2|4
void rand_num(void);
// 显示界面
void show_view(void);
// 方向处理
void up_move(void);
void down_move(void);
void left_move(void);
void right_move(void);
// 检查是否失败
bool is_over(void);
int main(int argc,const char* argv[])
{
for(;;)
{
rand_num();
show_view();
switch(getch())
{
case 183: up_move(); break;
case 184: down_move(); break;
case 185: right_move(); break;
case 186: left_move(); break;
}
if(is_over())
{
printf("游戏结束\n");
return 0;
}
}
}
~
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <getch.h>
#include <string.h>
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, 1, -1};
int d[4][4];
bool ok = false;
void print() {
system("clear");
for (int i = 0; i < 9; ++i) {
if (i % 2 == 0) {
puts("-----------------------------");
} else {
for (int j = 0; j < 4; ++j) if (d[i / 2][j] != 0) {
printf("|%6d", d[i / 2][j]);
} else {
printf("| ");
}
printf("|\n");
}
}
}
bool check() {
int cnt = 0;
ok = false;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
cnt += d[i][j] == 0;
for (int dir = 0; dir < 4; ++dir) {
int fx = i + dx[dir], fy = j + dy[dir];
if (fx >= 0 && fy >= 0 && fx < 4 && fy < 4 && d[fx][fy] == d[i][j] && d[i][j]) {
ok = true;
return true;
}
}
}
}
return cnt != 0;
}
void get() {
if (ok) {
return ;
}
int w = rand() % 2;
w = 1 << w + 1;
int x = rand() % 4, y = rand() % 4;
while (d[x][y] != 0) {
x = rand() % 4, y = rand() % 4;
}
d[x][y] = w;
}
int move() {
int dir = getch() - 183, score = 0;
int cpd[4][4], cp[4][4];
memcpy(cp, d, sizeof d);
if (dir == 0) {
for (int j = 0; j < 4; ++j) {
for (int k = 0; k < 4; ++k) {
for (int i = 1; i < 4; ++i) if (d[i - 1][j] == 0 && d[i][j]) {
d[i - 1][j] ^= d[i][j] ^= d[i - 1][j] ^= d[i][j];
}
}
}
memcpy(cpd, d, sizeof d);
for (int j = 0; j < 4; ++j) {
for (int i = 0; i < 4; ++i) {
int fx = dx[dir] + i, fy = dy[dir] + j;
if (fx >= 0 && fy >= 0 && fx < 4 && fy < 4 && cpd[fx][fy] == cpd[i][j] && cpd[fx][fy]) {
d[fx][fy] += d[i][j];
d[i][j] = 0;
score += d[fx][fy];
}
}
}
for (int j = 0; j < 4; ++j) {
for (int k = 0; k < 4; ++k) {
for (int i = 1; i < 4; ++i) if (d[i - 1][j] == 0 && d[i][j]) {
d[i - 1][j] ^= d[i][j] ^= d[i - 1][j] ^= d[i][j];
}
}
}
} else if (dir == 1) {
for (int j = 3; j >= 0; --j) {
for (int k = 0; k < 4; ++k) {
for (int i = 2; i >= 0; --i) if (d[i + 1][j] == 0 && d[i][j]) {
d[i + 1][j] ^= d[i][j] ^= d[i + 1][j] ^= d[i][j];
}
}
}
memcpy(cpd, d, sizeof d);
for (int j = 3; j >= 0; --j) {
for (int i = 3; i >= 0; --i) {
int fx = dx[dir] + i, fy = dy[dir] + j;
if (fx >= 0 && fy >= 0 && fx < 4 && fy < 4 && cpd[fx][fy] == cpd[i][j] && cpd[fx][fy]) {
d[fx][fy] += d[i][j];
d[i][j] = 0;
score += d[fx][fy];
}
}
}
for (int j = 3; j >= 0; --j) {
for (int k = 0; k < 4; ++k) {
for (int i = 2; i >= 0; --i) if (d[i + 1][j] == 0 && d[i][j]) {
d[i + 1][j] ^= d[i][j] ^= d[i + 1][j] ^= d[i][j];
}
}
}
} else if (dir == 2) {
for (int i = 3; i >= 0; --i) {
for (int k = 0; k < 4; ++k) {
for (int j = 2; j >= 0; --j) if (d[i][j + 1] == 0 && d[i][j]) {
d[i][j + 1] ^= d[i][j] ^= d[i][j + 1] ^= d[i][j];
}
}
}
memcpy(cpd, d, sizeof d);
for (int i = 3; i >= 0; --i) {
for (int j = 3; j >= 0; --j) {
int fx = dx[dir] + i, fy = dy[dir] + j;
if (fx >= 0 && fy >= 0 && fx < 4 && fy < 4 && cpd[fx][fy] == cpd[i][j] && cpd[fx][fy]) {
d[fx][fy] += d[i][j];
d[i][j] = 0;
score += d[fx][fy];
}
}
}
for (int i = 3; i >= 0; --i) {
for (int k = 0; k < 4; ++k) {
for (int j = 2; j >= 0; --j) if (d[i][j + 1] == 0 && d[i][j]) {
d[i][j + 1] ^= d[i][j] ^= d[i][j + 1] ^= d[i][j];
}
}
}
} else if (dir == 3) {
for (int i = 0; i < 4; ++i) {
for (int k = 0; k < 4; ++k) {
for (int j = 1; j < 4; ++j) if (d[i][j - 1] == 0 && d[i][j]) {
d[i][j - 1] ^= d[i][j] ^= d[i][j - 1] ^= d[i][j];
}
}
}
memcpy(cpd, d, sizeof d);
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
int fx = dx[dir] + i, fy = dy[dir] + j;
if (fx >= 0 && fy >= 0 && fx < 4 && fy < 4 && cpd[fx][fy] == cpd[i][j] && cpd[fx][fy]) {
d[fx][fy] += d[i][j];
d[i][j] = 0;
score += d[fx][fy];
}
}
}
for (int i = 0; i < 4; ++i) {
for (int k = 0; k < 4; ++k) {
for (int j = 1; j < 4; ++j) if (d[i][j - 1] == 0 && d[i][j]) {
d[i][j - 1] ^= d[i][j] ^= d[i][j - 1] ^= d[i][j];
}
}
}
}
ok = true;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) if (cp[i][j] != d[i][j]) {
ok = false;
}
}
return score;
}
int main() {
srand(time(0));
get(), print();
int score = 0, idx = 0;
while (check()) {
idx += 1, score += move();
get(), print();
}
printf("游戏已经结束,您的得分是%d, 共用了%d步\n", score, idx);
}
标签:fx,int,fy,补码,++,C语言,标准,&&
From: https://www.cnblogs.com/sleeeeeping/p/18173634