识别有效的IP地址

#include <iostream>
#include <string>
#include <vector>
#include <sstream>

using namespace std;
//  首先判断IP地址是否合法,是否属于ABCDE五大类
//..其次判断是否是私网IP,有一定范围
//..最后判断

bool IsValidIp(string ip)
{
    istringstream is(ip);
    string temp;
    int count = 0;
    while (getline(is,temp,'.')) {
        if(++count > 4 || temp.empty() || stoi(temp) > 255) {
            return false;
        }
    }
    return count == 4;
}

bool IsPrivate(string ip)
{
    istringstream is(ip);
    string temp;
    vector<int> vec;
    while (getline(is,temp,'.')) {
        vec.push_back(stoi(temp));
    }
    if (vec[0] == 10) {
        return true;
    }
    if (vec[0] == 172 && (vec[1] >= 16 && vec[1] <= 31)) {
        return true;
    }
    if (vec[0] == 192 && (vec[1] == 168)) {
        return true;
    }
    return false;
}

bool IsValidMask(string ip)
{
    istringstream is(ip);
    string temp;
    unsigned b = 0;
    while (getline(is,temp,'.')){
        b = (b << 8) + stoi(temp);
    }
    if (!b) return false;
    b = ~b + 1;
    if (b == 1) return false;
    if ((b & (b-1)) == 0) return true;
    return false;
}

int main(){
    string input;
    int a = 0,b = 0,c = 0,d = 0,e = 0,err = 0,p = 0;
    while(cin >> input){
        istringstream is(input);
        string add;
        vector<string> v;
        while(getline(is,add,'~')) v.push_back(add);
        if(!IsValidIp(v[1]) || !IsValidMask(v[1])) err++;
        else{
            if(!IsValidIp(v[0])) err++;
            else{
                int first = stoi(v[0].substr(0,v[0].find_first_of('.')));
                if(IsPrivate(v[0])) p++;
                if(first > 0 && first <127) a++;
                else if(first > 127 && first <192) b++;
                else if(first > 191 && first <224) c++;
                else if(first > 223 && first <240) d++;
                else if(first > 239 && first <256) e++;
            }
        }
    }
    cout << a << " " << b << " " << c << " " << d << " " << e << " " << err << " " << p << endl;
    return 0;
}

判断子网掩码

[C++][识别有效的IP地址和掩码并进行分类统计] 详细思路以及getline函数处理字符串技巧

题目要点:
所有的IP地址划分为 A,B,C,D,E五类:
A类地址1.0.0.0 ~ 126.255.255.255;
B类地址128.0.0.0 ~ 191.255.255.255;
C类地址192.0.0.0 ~ 223.255.255.255;
D类地址224.0.0.0 ~ 239.255.255.255;
E类地址240.0.0.0 ~ 255.255.255.255

私网IP范围是:
10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255

子网掩码为二进制下前面是连续的1,然后全是0。

输出:统计A、B、C、D、E、错误IP地址或错误掩码、私有IP的个数

一些需要注意的细节
类似于【0...】和【127...】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时可以忽略
私有IP地址和A,B,C,D,E类地址是不冲突的,也就是说需要同时+1
如果子网掩码是非法的,则不再需要查看IP地址
全零【0.0.0.0】或者全一【255.255.255.255】的子网掩码也是非法的
思路
按行读取输入,根据字符‘~’ 将IP地址与子网掩码分开
查看子网掩码是否合法。
合法,则继续检查IP地址
非法,则相应统计项+1,继续下一行的读入
查看IP地址是否合法
合法,查看IP地址属于哪一类,是否是私有ip地址;相应统计项+1
非法,相应统计项+1
具体实现
判断IP地址是否合法,如果满足下列条件之一即为非法地址
数字段数不为4
存在空段,即【192..1.0】这种
某个段的数字大于255
判断子网掩码是否合法,如果满足下列条件之一即为非法掩码
不是一个合格的IP地址
在二进制下,不满足前面连续是1,然后全是0
在二进制下,全为0或全为1
如何判断一个掩码地址是不是满足前面连续是1,然后全是0?
将掩码地址转换为32位无符号整型,假设这个数为b。如果此时b为0,则为非法掩码
将b按位取反后+1。如果此时b为1,则b原来是二进制全1,非法掩码
如果b和b-1做按位与运算后为0,则说明是合法掩码,否则为非法掩码


我觉得我的思路很清晰,描述也详尽准确,觉得有用请点赞鼓励

合法的子网掩码:
前面全是1后面全是0,比如255.255.0.0(前16位为1后16位为0),也比如255.252.0.0(前14位为1后18位为0),后者也是合法的子网掩码,不要将前面全是1理解为前面整8位为1
0.0.0.0 和 255.255.255.255 均不合法

合法的ip:
题目列出的A ~ E五大类 以及 0.0.0.0 ~ 0.255.255.255 和 127.0.0.0 ~ 127.255.255.255

注意:
0.0.0.0 ~ 0.255.255.255 和 127.0.0.0 ~ 127.255.255.255为合法ip但不属于A~E类任一类
私人ip在A ~ E五大类ip范围内,私人ip计数值和相应某类ip计数值都要加1
第六项计数值——错误IP地址或错误掩码的意思是对于输入的某个字符串“ip ~ 子网掩码”,其中的ip与子网掩码只有一个错则计数值加1,ip与子网掩码同时错则计数值也只加1而不是加2

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

int typeofip(string ip){ //判断ip是否合法,不合法返回0,合法的话进一步判断是否是私人ip以及属于A~E哪一类
    vector<int> vi;
    int dot=ip.find_first_of('.');
    while(dot!=-1)
    {
        int a;
        stringstream s;
        s<<ip.substr(0,dot);
        s>>a;
        vi.push_back(a);
        ip=ip.substr(dot+1,ip.size());
        dot=ip.find_first_of('.');
    }
    int a;
    stringstream s;
    s<<ip;
    s>>a;
    vi.push_back(a);
    if(vi.size()!=4) return 0;   //不够4个数或者多于4个数的ip非法
    for(int i=0;i<4;i++)  //ip的4个数任一个不在0~255范围内则ip非法
        if(vi[i]<0||vi[i]>255) 
            goto ZERO;       
    if(vi[0]==0 || vi[0]==127) return 6; //0或者127开头的ip合法但是不属于A~E五大类ip中的任一类
    else if(vi[0]==10) return 10; //私人ip 10.0.0.0~10.255.255.255
    else if(vi[0]>=1 && vi[0]<=126) return 1; //非私人ip的A类ip
    else if( vi[0]==172 && (vi[1]>=16&&vi[1]<=31) ) return 172; //私人ip 172.16.0.0~172.31.255.255
    else if(vi[0]>=128&&vi[0]<=191) return 2; //非私人ip的B类ip
    else if(vi[0]==192&&vi[1]==168) return 192; //私人ip 192.168.0.0~192.168.255.255
    else if(vi[0]>=192&&vi[0]<=223) return 3; //非私人ip的C类ip
    else if(vi[0]>=224&&vi[0]<=239) return 4; //D类ip
    else if(vi[0]>=240&&vi[0]<=255) return 5; //E类ip
    ZERO:return 0;
}

int ismask(string m){ //判断子网掩码是否合法,合法返回1,不合法返回0
    vector<int> vi;
    int dot=m.find_first_of('.');
    while(dot!=-1)
    {
        unsigned int a;  //注意一定是无符号数
        stringstream s;
        s<<m.substr(0,dot);
        s>>a;
        vi.push_back(a);
        m=m.substr(dot+1,m.size());
        dot=m.find_first_of('.');
    }
    unsigned int a;  //注意一定是无符号数
    stringstream s;
    s<<m;
    s>>a;
    vi.push_back(a);
    if(vi.size()!=4) return 0;  //不够4个数或者多于4个数的子网掩码非法
    for(int i=0;i<4;i++)  //子网掩码的4个数任一个不在0~255范围内则子网掩码非法
        if(vi[i]<0||vi[i]>255) 
            return 0;     
    unsigned int b=0;  //注意一定是无符号数
    for(int i=0;i<4;i++)  //求出将子网掩码的4个数均化为二进制数后依序拼接成的32位二进制数,放入b中
    {
        b+=vi[i]<<(3-i)*8;
    }
    if(b==4294967295||b==0) return 0; //全1或全0的子网掩码是非法的,其中4294967295=2^32-1化为2进制为32个1
    b=~b+1; //合法的子网掩码取反后前面全是0后面全是1,再加1得到这样一个二进制数:其中一位为1,1的前后均为0。即为2次幂
    if((b&(b-1))==0) return 1;  //判断b是否为二次幂,若是则子网掩码合法,返回1;若不是,则子网掩码不合法,返回0
    else return 0;
}

int main(){
    string s;
    vector<string> vs;
    while(getline(cin,s))
        vs.push_back(s);
    int suma=0,sumb=0,sumc=0,sumd=0,sume=0,sumerr=0,sumpri=0;
    for(int i=0;i<vs.size();i++)
    {
        string tmp1,tmp2,tmp=vs[i];
        int wave=tmp.find('~');
        tmp1=tmp.substr(0,wave);
        tmp2=tmp.substr(wave+1,tmp.size());
        if(typeofip(tmp1)==0||ismask(tmp2)==0) sumerr++;
        else if(typeofip(tmp1)==10) {suma++;sumpri++;}
        else if(typeofip(tmp1)==172) {sumb++;sumpri++;}
        else if(typeofip(tmp1)==192) {sumc++;sumpri++;}
        else if(typeofip(tmp1)==1) suma++;
        else if(typeofip(tmp1)==2) sumb++;
        else if(typeofip(tmp1)==3) sumc++;
        else if(typeofip(tmp1)==4) sumd++;
        else if(typeofip(tmp1)==5) sume++;
    }
    cout<<suma<<' '<<sumb<<' '<<sumc<<' '<<sumd<<' '<<sume<<' '<<sumerr<<' '<<sumpri<<endl;
    return 0;
}