標準C語言5

sleeeeeping發表於2024-05-05

進位制轉換:

​ 現在的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);
}

相關文章