C++ 實現校驗和計算(無取反步驟)


題目

編寫一個計算機程序用來計算一個文件的16位效驗和。最快速的方法是用一個32位的整數來存放這個和。記住要處理進位(例如,超過16位的那些位),把它們加到效驗和中。

  • 要求:
    1. 以命令行形式運行:check_sum infile。其中check_sum為程序名,infile為輸入數據文件名。
    2. 輸出:數據文件的效驗和
  • 附:效驗和(checksum)
    - 原理:把要發送的數據看成16比特的二進制整數序列,並計算他們的和。若數據字節長度為奇數,則在數據尾部補一個字節的0以湊成偶數。
    - 例子:16位效驗和計算,下圖表明一個小的字符串的16位效驗和的計算。為了計算效驗和,發送計算機把每對字符當成16位整數處理並計算效驗和。如果效驗和大於16位,那么把進位一起加到最后的效驗和中。

本地數據樣式

分析

  1. 這道題的校驗和沒有要求最后取反,實際上求和后是要取反的;
  2. 原理不難理解,就是數據轉換成十六進制,然后十六進制求和。四位十六進制,所以也要求進位加到結果中;
  3. 難點在於字符轉十六進制,十六進制有進位相加(我這里是用string存儲十六進制數,可能網上還有更直接的十六進制的存儲方式和計算方式);
  4. 先用char類型數組把數據逐個存進數組中;
  5. 將每兩個char字符轉為四位十六進制,其中會先將每個char字符先轉為二位十六進制;
  6. 最后進行十六進制的求和,我沒有選擇將進位留到最后再相加,而是每一次運算都完成進位的相加,因為經過多次運算后,不能確定進位的位數。

程序流程圖

代碼

#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;

//命令行輸入
void waitInput(string command, string &infile) {
	cout << "Please input check_sum infile, infile is the file name!" << endl;
	cin >> command >> infile;
	while (command != "check_sum") {
		cout << "Wrong command! Please reenter!" << endl;
		cin >> command >> infile;
	}
	cout << endl;
}

//一個字符轉二位十六進制
string CToH(char charIndex) {
	//char強制轉換為int
	int temp = charIndex;
	//十六進制的一二位(現在是十進制)
	int first = temp / 16;
	int second = temp % 16;
	//十進制轉十六進制(用srting存)
	string res;
	string resFirst;
	string resSecond;
	if (first < 10) resFirst.append(to_string(first));
	if (second < 10) resSecond.append(to_string(second));
	if (first >= 10) {
		switch (first) {
		case 10:	resFirst.append("A"); break;
		case 11:	resFirst.append("B"); break;
		case 12:	resFirst.append("C"); break;
		case 13:	resFirst.append("D"); break;
		case 14:	resFirst.append("E"); break;
		case 15:	resFirst.append("F"); break;
		}
	}
	if (second >= 10) {
		switch (second) {
		case 10:	resSecond.append("A"); break;
		case 11:	resSecond.append("B"); break;
		case 12:	resSecond.append("C"); break;
		case 13:	resSecond.append("D"); break;
		case 14:	resSecond.append("E"); break;
		case 15:	resSecond.append("F"); break;
		}
	}
	res.append(resFirst);
	res.append(resSecond);
	return res;
}

//每對字符轉為四位十六進制
string makePairChar(char firstChar, char secondChar) {
	//兩string相加即可
	return CToH(firstChar) + CToH(secondChar);
}

//四位十六進制相加
void sum(string &first, string second) {
	//進位
	int carryInt = 0;
	for (int i = 3; i >= 0; i--) {
		//先將計算的該位轉為十進制
		int firstInt;
		int secondInt;
		int res;
		if(first[i] <= '9') firstInt = (int)first[i] - '0';
		else firstInt = (int)first[i] - 55;
		if (second[i] <= '9') secondInt = (int)second[i] - '0';
		else secondInt = (int)second[i] - 55;
		//獲得十進制結果
		res = firstInt + secondInt + carryInt;
		//進位歸零
		carryInt = 0;
		//結果轉換為char,存進string
		if (res < 10) first[i] = res + '0';
		else if (res >= 10 && res <= 15) first[i] = 'A' + res - 10;
		else {
			if (res > 15 && res < 26) first[i] = res - 16 + '0';
			else first[i] = 'A' + res - 26;
			carryInt = 1;
		}
	}
	//若四位都運算完成后,有第五位的進位,則繼續和進位運算,消除進位
	if (carryInt) {
		string carry = "0001";
		sum(first, carry);
	}
}

int main() {
	//等待命令行輸入
	string infile, command;
	waitInput(command, infile);
	
	//打開文件
	ifstream dataFile(infile);
	if (!dataFile.is_open()) {
		cout << "dataFile文件打開失敗!" << endl;
		return 1;
	}

	//將文件所有字符存進數組
	//最后一個字符為-1,不存進數組
	cout << "文件數據:" << endl;
	vector<char> dataArray;
	while (!dataFile.eof()){
		char str = dataFile.get();
		cout << str;
		if ((int)str == -1) continue;
		dataArray.push_back(str);
	}
	cout << endl << endl;
	//用完關閉
	dataFile.close();

	//把每對字符當成16位整數處理
	//用string數組存每對字符的16進制數
	vector<string> pairChar;
	//判斷奇數個字符還是偶數個字符
	int remainder = dataArray.size() % 2;
	//若是奇數個,循環走到倒數第二個
	//若是偶數個,循環走到倒數第一個
	for (unsigned  int i = 0; i < dataArray.size() - remainder; i += 2) {
		string pairCharIndex = makePairChar(dataArray[i], dataArray[i + 1]);
		pairChar.push_back(pairCharIndex);
	}

	//若數據字節長度為奇數,則在數據尾部補一個字節的0以湊成偶數
        //一字節0也就是空字符,空字符就是\0
	if (remainder) {
		string pairCharIndex = makePairChar(dataArray[dataArray.size() - 1], '\0');
		pairChar.push_back(pairCharIndex);
	}

	//計算校驗和
	string res = pairChar[0];
	for (unsigned  int i = 1; i < pairChar.size(); i++) sum(res, pairChar[i]);

	//打印結果
	cout << "校驗和:" << endl;
	cout << res << endl;

	return 0;
}

結果截圖

  • 數據為例子(答案相同)

  • 數據增加一行


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM