做笔试遇到了关于掩码、子网容量的相关计算,完全没概念,于是去复习

这是笔记

总得来说,掩码是因为子网划分而存在的,通过掩码可以确定一个标准网络号下的子网号,进而确定子网容量
复习完就想亲手写一个程序,完成对一个IP地址的解读和转化

  1. 可以复习知识点
  2. 下次遇到的时候可以直接用自己写的程序快速得出想要的信息,效率高
  3. 可以锻炼基础的编程能力

我在想,要是当初学计网、机组、特别是数据结构与算法的时候能这样做,我现在该有多大的提升呀
悟已往之不谏,知来者之可追

在写的过程中,不可避免地要实现将点分十进制的IP地址输入转换为二进制,这里有两种表示,1是以十进制整型表示,2是以01字符转的形式表示
我因为需要对二进制的每一位操作,同时也是最直接的转换思路:

  1. 以字符串形式整行读入
  2. 取出以“.”分隔的四个数字,并保存在一个int数组中
  3. 对每一个数字转换成8位int字符串并拼接得到最终的01字符串
    这个过程中遇到了好几个字符串处理相关的函数,比如:
  • 字符串转整数stoi()stol()系列
  • strcpy()用来复制字符串,和c_str()配合使用,后者用来返回当前字符串的首地址,const char*类型
  • strtok()用来将字符串以指定字符分隔

值得一提的是上面两个函数都遇到了不安全问题,不得不用_s的安全版本

但是得到了01字符串仍然是不够的,依旧需要十进制的二进制表示,用于运算
我用了很直接也很初级的办法,对01字符串扫描,位权相加
以下是目前的成果

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

/*
* 这是一个IP地址相关的计算器
*/

// 检查IP地址是否合法
void check(string ipAddress) {

}

vector<int> splitIpAddress(const string& str) {
	vector<int> res;
	// if (str.empty()) return res;

	// 需要先将string转成char*类型
	// 准备一个char数组
	char* chars = new char[str.size() + 1];
	// c_str返回当前字符串的首地址
	// 将字符串中的每个字符拷贝到字符数组中去
	strcpy_s(chars, str.size() + 1, str.c_str());

	// 定义分隔符
	const char* delim = ".";
	// 返回从头开始的被分割的字符串,没有时则返回null

	char* next_token = NULL;
	char* p = strtok_s(chars, delim, &next_token);
	while (p) {
		res.push_back(stoi(p));
		p = strtok_s(NULL, delim, &next_token);
	}
	return res;
}

// 将点分十进制IP地址转换为32位长度的01字符串
string transferIpToString(string ipAddress) {
	string binaryAddress;
	// 将用作分隔的点去掉,返回一个4位string的数组
	vector<int> nums = splitIpAddress(ipAddress);
	// 将4位string分别转为8位01字符串并拼接起来,返回
	for (int num : nums) binaryAddress += bitset<8>(num).to_string();
	return binaryAddress;
}


int toInt(string str) {
	int res = 0;
	// 已知这个字符串是32位长度
	for (int i = 0; i < 32; i++) {
		if (str[i] == '1') {
			res += 1 << (31 - i);
		}
	}
	return res;
}

// 判断IP地址类型
char judgeType(string binaryIpAddress) {
	if (binaryIpAddress[0] == '0') return 'A';
	else if (binaryIpAddress[1] == '0') return 'B';
	else if (binaryIpAddress[2] == '0') return 'C';
	else if (binaryIpAddress[3] == '0') return 'D';
	else return 'E';
}


void subnetting(string binaryIpAddress,string mask) {
	int networkNumberRow;
	char networkType;
	// 判断IP地址类型
	cout << "网络地址类型为:";
	if (binaryIpAddress[0] == '0') {
		networkType = 'A';
		networkNumberRow = 8;
	}
	else if (binaryIpAddress[1] == '0') {
		networkType = 'B';
		networkNumberRow = 16;
	}
	else if (binaryIpAddress[2] == '0') {
		networkType = 'C';
		networkNumberRow = 24;
	}
	else if (binaryIpAddress[3] == '0') networkType = 'D';
	else networkType = 'E';
	cout << "网络地址类型为:" << networkType << endl;
	// 判断是否进行了子网划分
	// 根据判断的网络类型,推出应有的网络号长度,再与与运算之后得到的作比较
	// toInt(binaryIpAddress)&
	cout << "带子网号的网络号为:" << endl;
}

// 直接将IP地址转换为二进制,并以10进制整形表示
int transferIp(string ipAddress) {
	return 0;
}

int main() {

	// 获取输入
	cout << "请输入IP地址:"<<endl;
	string ipAddress;
	getline(cin, ipAddress);
	cout << "请输入掩码:" << endl;
	string mask;
	getline(cin, mask);

	// 将点分十进制转换为32位长度的01字符串
	string binaryIpAddress = transferIpToString(ipAddress);
	cout << "IP地址转换为二进制表示为:" << binaryIpAddress<<endl;
	int binaryIpAddressToInt = toInt(binaryIpAddress);
	cout << "十进制表示二进制IP地址为:" << binaryIpAddressToInt <<endl;
	// 判断IP地址类型

	// 判断是否进行子网划分以及子网号是多少


	return 0;
}

在这一过程中我也看到了牛客网上有这一主题的题目,做IP地址点分十进制与二进制的相互转换,然后这里有一个直呼NB的写法

int main() {
	long long n, a1, a2, a3, a4;
	char ch;
	while (cin >> a1 >> ch >> a2 >> ch >> a3 >> ch >> a4) {
		cin >> n;
		long long res = 0;
		res += (a1 << 24) + (a2 << 16) + (a3 << 8) + a4;
		a1 = n >> 24;
		// 这里&255运算表示取右移后的最后8位
		a2 = (n >> 16) & 255;
		a3 = (n >> 8) & 255;
		a4 = n & 255;
		cout << res << endl << a1 << '.' << a2 << '.' << a3 << '.' << a4 << endl;
	}
	return 0;
}
  1. 1是没想到可以这样获取输入,直接就把分隔拆分的问题解决了
  2. 2是全部利用移位运算(虽然我也有使用到),短短十几行代码就把问题解决了