IP地址与二进制互转
做笔试遇到了关于掩码、子网容量的相关计算,完全没概念,于是去复习
这是笔记
总得来说,掩码是因为子网划分而存在的,通过掩码可以确定一个标准网络号下的子网号,进而确定子网容量
复习完就想亲手写一个程序,完成对一个IP地址的解读和转化
- 可以复习知识点
- 下次遇到的时候可以直接用自己写的程序快速得出想要的信息,效率高
- 可以锻炼基础的编程能力
我在想,要是当初学计网、机组、特别是数据结构与算法的时候能这样做,我现在该有多大的提升呀
悟已往之不谏,知来者之可追
在写的过程中,不可避免地要实现将点分十进制的IP地址输入转换为二进制,这里有两种表示,1是以十进制整型表示,2是以01字符转的形式表示
我因为需要对二进制的每一位操作,同时也是最直接的转换思路:
- 以字符串形式整行读入
- 取出以“.”分隔的四个数字,并保存在一个int数组中
- 对每一个数字转换成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是没想到可以这样获取输入,直接就把分隔拆分的问题解决了
- 2是全部利用移位运算(虽然我也有使用到),短短十几行代码就把问题解决了