题解 | #识别有效的IP地址和掩码并进行分类统计#
识别有效的IP地址和掩码并进行分类统计
https://www.nowcoder.com/practice/de538edd6f7e4bc3a5689723a7435682
#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
#include <bitset>
using namespace std;
//思路:(首先排除0.*.*.* 和127.*.*.* 的IP地址 ,因为这种IP地址不属于任何一类需要计数的类型)
//1.判断子网掩码是否正确:错误属于IP或掩码错误情况,相应计数加1,继续下一条字符串判断,重新开始1;正确进入2
//2.此时掩码正确,判断IP地址是否正确:错误属于IP或掩码错误情况,相应计数加1,继续下一条字符串判断,重新开始1;正确进入3
//3.此时IP正确,判段属于A/B/C/D/E哪类地址,同时判断是否属于私有地址,相应计数加1,继续下一条字符串判断,重新开始1
int main(){
string mstr;
//计数变量
int Aaddress = 0;
int Baddress = 0;
int Caddress = 0;
int Daddress = 0;
int Eaddress = 0;
int ErrorIpOrMask = 0;
int PrivateIP = 0;
while (getline(cin, mstr)){//循环处理多个字符串
//**************************************************************************************//
//获取两个字符串 , IP地址和子网掩码
int len = mstr.length();//单个字符串的长度
int Middle = mstr.find('~'); //查找 ~ 的位置
string strIp = mstr.substr(0,Middle);//存放单个字符串Ip地址部分//stringA.substr(int startIndex, int needLength)
string strMask = mstr.substr(Middle+1,len - Middle- 1 );//存放单个字符串子网掩码部分
//**************************************************************************************//
//排除0.*.*.* 和127.*.*.* 的IP地址
int ipPoint1 = strIp.find('.');
string ip1 = strIp.substr(0, ipPoint1);
if(ip1 == "0" || ip1 == "127"){
continue;
}
//**************************************************************************************//
//判断子网掩码是否正确
int maskPoint1 = strMask.find( '.' );//查找子网掩码中第1个点
string mask1 = strMask.substr(0 ,maskPoint1);
if( mask1 == "" || stoi(mask1) > 255 ){ //不能为空位
ErrorIpOrMask++;
continue;
}
bitset<8> bMask1(stoi(mask1)); //将字符串形式的数字转为整型后,获取其8位二进制值
int maskPoint2 = strMask.find( '.' , maskPoint1 + 1);//从maskPoint1 + 1位置开始,查找子网掩码中第2个点
string mask2 = strMask.substr(maskPoint1 + 1 , maskPoint2 - maskPoint1 - 1 );
if( mask2 == "" || stoi(mask2) > 255 ){ //不能为空位
ErrorIpOrMask++;
continue;
}
bitset<8> bMask2(stoi(mask2));
int maskPoint3 = strMask.find( '.' ,maskPoint2 + 1);//查找子网掩码中第一个点
string mask3 = strMask.substr(maskPoint2 + 1, maskPoint3 - maskPoint2 -1 );
if( mask3 == "" || stoi(mask3) > 255 ){ //不能为空位
ErrorIpOrMask++;
continue;
}
bitset<8> bMask3(stoi(mask3));
string mask4 = strMask.substr(maskPoint3+1 , strMask.length() - maskPoint3 -1 );
if( mask4 == "" || stoi(mask4) > 255 ){ //不能为空位
ErrorIpOrMask++;
continue;
}
bitset<8> bMask4(stoi(mask4));
//子网掩码 全0非法 , 全1 非法
if(bMask1.count() + bMask2.count() + bMask3.count() + bMask4.count() == 32 ||
bMask1.count()+ bMask2.count() + bMask3.count() + bMask4.count() == 0){
ErrorIpOrMask++;
continue;
}
int vMask[32] = {0};//将二进制的子网掩码放入整型数组vMask,用于判断子网掩码中的连续1
for(int i = 0 ; i< 32 ;i++){
if(i>=0 && i<= 7){
vMask[i] = bMask1[7 - i];
}
else if(i>=8 && i<= 15){
vMask[i] = bMask2[ 7 - i + 8];
}
else if(i>=16 && i <= 23){
vMask[i] = bMask3[7 - i+ 16];
}
else if(i>=24 && i< 31){
vMask[i] = bMask4[7- i + 24];
}
}
bool ErrorContinue = false; //判断是否存在连续的1 ,不连续1非法 i,j 双指针判断
for(int i = 0 , j = 1 ; j < 32 ; ){
if(vMask[i] == 0 && vMask[j] == 1){ //对一串子网掩码而言,出现 ****01***即是非法的掩码
ErrorContinue = true;
break;
}
i++;
j++;
}
if(ErrorContinue){
ErrorIpOrMask++;
continue;
}
//**********************************************************************************//
//判断IP地址是否正确
if(ip1 == "" || stoi(ip1) > 255 ){
ErrorIpOrMask++;
continue;
}
int ipPoint2 = strIp.find('.' , ipPoint1 +1 );
string ip2 = strIp.substr(ipPoint1 + 1, ipPoint2 - ipPoint1 - 1);
if(ip2 == "" || stoi(ip2) > 255){
ErrorIpOrMask++;
continue;
}
int ipPoint3 = strIp.find('.' , ipPoint2 +1 );
string ip3 = strIp.substr(ipPoint2 + 1, ipPoint3 - ipPoint2 - 1);
if(ip3 == "" || stoi(ip3) > 255){
ErrorIpOrMask++;
continue;
}
string ip4 = strIp.substr(ipPoint3 + 1 , strIp.length() - ipPoint3 - 1);
if(ip4 == "" || stoi(ip4) > 255){
ErrorIpOrMask++;
continue;
}
//**************************************************************************************//
//判断属于哪一类IP地址
int judge1 = stoi(ip1);
int judge2 =stoi(ip2);
if(judge1 >= 1 && judge1 <=126){ // A 类
Aaddress++;
if(judge1 == 10){
PrivateIP++;
}
}
else if(judge1 >= 128 && judge1<= 191){ // B 类
Baddress++;
if(judge1 == 172 && judge2 >= 16 && judge2 <= 31){
PrivateIP++;
}
}
else if(judge1 >= 192 && judge1 <= 223){// C 类
Caddress++;
if(judge2 == 168){
PrivateIP++;
}
}
else if(judge1 >= 224 && judge1 <= 239){// D 类
Daddress++;
}
else if(judge1 >= 240 && judge1 <= 255){// E 类
Eaddress++;
}
}
cout<<Aaddress<<" "<<Baddress<<" "<<Caddress<<" "<<Daddress<<" "<<Eaddress<<" "<<ErrorIpOrMask<<" "<<PrivateIP<<" "<<endl;
}
整体的解题思路在代码中有详细的注释,个人认为这道题主要难点在于细节的处理。
- 第一,是对IP地址的特殊情况处理,在判断子网掩码前需要排除 0.*.*.* 和 127.*.*.* 的IP地址 ,因为这种IP地址不属于任何一类需要计数的类型;
- 第二,不论是对于IP地址还是子网掩码而言,都必须符合 a . b . c. d 这种格式,19.8..8 这种属于非法的IP地址,这一点在题目中也有提到,可以通过判断a/b/c/d位是否为空来排除错误情况,并且为了保证可以将a/b/c/d转换为8位的二进制,还需要在转换为比特数之前判断a/b/c/d是否处于0- 255 的区间;
- 第三,是对子网掩码判断,不考虑和IP地址相适配的情况下,对于一个合法的子网掩码来说,由连续的1 加连续的0 共32比特组成;(关于子网掩码和 IP地址相适配,是说:对于A类地址,可指派的网络号最小为1,最大为126, 即8位网络号和24位的主机号,在划分子网的情况下,子网掩码不再是255.0.0.0,且连1大于8,不适配是在连1长度小于8的情况下;对于B类地址,16位的网络号和16位的主机号;对于C 类地址,由24位网络号和8位的主机号组成 )。本题的测试用例好像默认是相互适配的,当然在划分子网的情况下,如前所述,借用一部分的主机位来充当网络位是完全正确的。
查看6道真题和解析