题解 | #识别有效的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位的主机号组成 )。本题的测试用例好像默认是相互适配的,当然在划分子网的情况下,如前所述,借用一部分的主机位来充当网络位是完全正确的。