侧边栏壁纸
    • 累计撰写 302 篇文章
    • 累计收到 527 条评论
    华为C++算法-识别有效的IP地址和掩码并进行分类统计
    我的学记|刘航宇的博客

    华为C++算法-识别有效的IP地址和掩码并进行分类统计

    刘航宇
    2023-12-11 / 0 评论 / 178 阅读 / 正在检测是否收录...

    问题

    请解析IP地址和对应的掩码,进行分类识别。要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类。

    所有的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。(例如:255.255.255.32就是一个非法的掩码)
    (注意二进制下全是1或者全是0均为非法子网掩码)

    注意:

    1. 类似于【0...】和【127...】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时请忽略
    2. 私有IP地址和A,B,C,D,E类地址是不冲突的

    输入描述:

    多行字符串。每行一个IP地址和掩码,用~隔开。

    输出描述:

    统计A、B、C、D、E、错误IP地址或错误掩码、私有IP的个数,之间以空格隔开。

    示例


    示例2

    需要注意的细节

    类似于【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,则说明是合法掩码,否则为非法掩码

    代码

    注意getline函数可以指定分割字符串的字符

    // 引入输入输出流、字符串、字符串流和向量等头文件
    #include<iostream>
    #include<string>
    #include<sstream>
    #include<vector>
    // 使用标准命名空间
    using namespace std;
    
    // 定义一个函数,判断一个字符串是否是合法的IP地址
    bool judge_ip(string ip){
        // 定义一个整数变量,记录IP地址的段数
        int j = 0;
        // 定义一个字符串流对象,用于分割IP地址
        istringstream iss(ip);
        // 定义一个字符串变量,用于存储IP地址的每一段
        string seg;
        // 使用循环,以'.'为分隔符,获取IP地址的每一段
        while(getline(iss,seg,'.'))
            // 如果段数加一大于4,或者该段为空,或者该段的数值大于255,说明不是合法的IP地址,返回false
            if(++j > 4 || seg.empty() || stoi(seg) > 255)
                return false;
        // 如果循环结束后,段数等于4,说明是合法的IP地址,返回true
        return j == 4;
    }
    
    // 定义一个函数,判断一个字符串是否是私有的IP地址
    bool is_private(string ip){
        // 定义一个字符串流对象,用于分割IP地址
        istringstream iss(ip);
        // 定义一个字符串变量,用于存储IP地址的每一段
        string seg;
        // 定义一个整数向量,用于存储IP地址的每一段的数值
        vector<int> v;
        // 使用循环,以'.'为分隔符,获取IP地址的每一段,并将其转换为整数,存入向量中
        while(getline(iss,seg,'.')) v.push_back(stoi(seg));
        // 如果IP地址的第一段等于10,说明是私有的IP地址,返回true
        if(v[0] == 10) return true;
        // 如果IP地址的第一段等于172,并且第二段在16到31之间,说明是私有的IP地址,返回true
        if(v[0] == 172 && (v[1] >= 16 && v[1] <= 31)) return true;
        // 如果IP地址的第一段等于192,并且第二段等于168,说明是私有的IP地址,返回true
        if(v[0] == 192 && v[1] == 168) return true;
        // 如果以上条件都不满足,说明不是私有的IP地址,返回false
        return false;
    }
    
    // 定义一个函数,判断一个字符串是否是合法的子网掩码
    bool is_mask(string ip){
        // 定义一个字符串流对象,用于分割IP地址
        istringstream iss(ip);
        // 定义一个字符串变量,用于存储IP地址的每一段
        string seg;
        // 定义一个无符号整数变量,用于存储IP地址的二进制表示
        unsigned b = 0;
        // 使用循环,以'.'为分隔符,获取IP地址的每一段,并将其转换为整数,左移8位后与b进行按位或运算,得到IP地址的二进制表示
        while(getline(iss,seg,'.')) b = (b << 8) + stoi(seg);
        // 如果b等于0,说明不是合法的子网掩码,返回false
        if(!b) return false;
        // 将b按位取反后加一,得到b的补码
        b = ~b + 1;
        // 如果b等于1,说明不是合法的子网掩码,返回false
        if(b == 1) return false;
        // 如果b与b减一进行按位与运算,结果等于0,说明b只有一个1,说明是合法的子网掩码,返回true
        if((b & (b-1)) == 0) return true;
        // 如果以上条件都不满足,说明不是合法的子网掩码,返回false
        return false;
    }
    
    // 定义主函数
    int main(){
        // 定义一个字符串变量,用于存储输入的IP地址和子网掩码
        string input;
        // 定义七个整数变量,用于统计A、B、C、D、E类地址、错误地址和私有地址的个数
        int a = 0,b = 0,c = 0,d = 0,e = 0,err = 0,p = 0;
        // 使用循环,读取输入的IP地址和子网掩码,直到输入结束
        while(cin >> input){
            // 定义一个字符串流对象,用于分割IP地址和子网掩码
            istringstream is(input);
            // 定义一个字符串变量,用于存储IP地址或子网掩码
            string add;
            // 定义一个字符串向量,用于存储IP地址和子网掩码
            vector<string> v;
            // 使用循环,以'~'为分隔符,获取IP地址和子网掩码,并存入向量中
            while(getline(is,add,'~')) v.push_back(add);
            // 如果IP地址或子网掩码不合法,错误地址的个数加一
            if(!judge_ip(v[1]) || !is_mask(v[1])) err++;
            else{
                // 如果IP地址不合法,错误地址的个数加一
                if(!judge_ip(v[0])) err++;
                else{
                    // 获取IP地址的第一段的数值
                    int first = stoi(v[0].substr(0,v[0].find_first_of('.')));
                    // 如果IP地址是私有的,私有地址的个数加一
                    if(is_private(v[0])) p++;
                    // 根据IP地址的第一段的数值,判断IP地址的类别,并相应的类别的个数加一
                    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++;
                }
            }
        }
        // 输出A、B、C、D、E类地址、错误地址和私有地址的个数
        cout << a << " " << b << " " << c << " " << d << " " << e << " " << err << " " << p << endl;
        // 返回0,表示程序正常结束
        return 0;
    }
    
    0
    【嵌软】STM32的4种开发方式介绍
    « 上一篇 2023-12-20
    大疆题解:跨时钟域脉冲信号处理—脉冲同步器(快到慢)
    下一篇 » 2023-12-11

    评论 (0)

    取消