c++ 整数取反_C++ 实现校验和计算(无取反步骤)

题目

编写一个计算机程序用来计算一个文件的16位效验和。最快速的方法是用一个32位的整数来存放这个和。记住要处理进位(例如,超过16位的那些位),把它们加到效验和中。

要求:

1. 以命令行形式运行:check_sum infile。其中check_sum为程序名,infile为输入数据文件名。

2. 输出:数据文件的效验和

附:效验和(checksum)

- 原理:把要发送的数据看成16比特的二进制整数序列,并计算他们的和。若数据字节长度为奇数,则在数据尾部补一个字节的0以凑成偶数。

- 例子:16位效验和计算,下图表明一个小的字符串的16位效验和的计算。为了计算效验和,发送计算机把每对字符当成16位整数处理并计算效验和。如果效验和大于16位,那么把进位一起加到最后的效验和中。

本地数据样式

分析

这道题的校验和没有要求最后取反,实际上求和后是要取反的;

原理不难理解,就是数据转换成十六进制,然后十六进制求和。四位十六进制,所以也要求进位加到结果中;

难点在于字符转十六进制,十六进制有进位相加(我这里是用string存储十六进制数,可能网上还有更直接的十六进制的存储方式和计算方式);

先用char类型数组把数据逐个存进数组中;

将每两个char字符转为四位十六进制,其中会先将每个char字符先转为二位十六进制;

最后进行十六进制的求和,我没有选择将进位留到最后再相加,而是每一次运算都完成进位的相加,因为经过多次运算后,不能确定进位的位数。

程序流程图

代码

#include

#include

#include

#include

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 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 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;

}

结果截图

数据为例子(答案相同)

数据增加一行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值