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

识别有效的IP地址和掩码并进行分类统计

http://www.nowcoder.com/questionTerminal/de538edd6f7e4bc3a5689723a7435682

题目要点:

所有的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的个数

一些需要注意的细节

  1. 类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时可以忽略
  2. 私有IP地址和A,B,C,D,E类地址是不冲突的,也就是说需要同时+1
  3. 如果子网掩码是非法的,则不再需要查看IP地址
  4. 全零【0.0.0.0】或者全一【255.255.255.255】的子网掩码也是非法的

思路

  1. 按行读取输入,根据字符‘~’ 将IP地址与子网掩码分开
  2. 查看子网掩码是否合法。
    • 合法,则继续检查IP地址
    • 非法,则相应统计项+1,继续下一行的读入
  3. 查看IP地址是否合法
    • 合法,查看IP地址属于哪一类,是否是私有ip地址;相应统计项+1
    • 非法,相应统计项+1

具体实现

  1. 判断IP地址是否合法,如果满足下列条件之一即为非法地址
    • 数字段数不为4
    • 存在空段,即【192..1.0】这种
    • 某个段的数字大于255
  2. 判断子网掩码是否合法,如果满足下列条件之一即为非法掩码
    • 不是一个合格的IP地址
    • 在二进制下,不满足前面连续是1,然后全是0
    • 在二进制下,全为0或全为1
  3. 如何判断一个掩码地址是不是满足前面连续是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;

bool judge_ip(string ip){
    int j = 0;
    istringstream iss(ip);
    string seg;
    while(getline(iss,seg,'.'))
        if(++j > 4 || seg.empty() || stoi(seg) > 255)
            return false;
    return j == 4;
}

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

bool is_mask(string ip){
    istringstream iss(ip);
    string seg;
    unsigned b = 0;
    while(getline(iss,seg,'.')) b = (b << 8) + stoi(seg);
    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(!judge_ip(v[1]) || !is_mask(v[1])) err++;
        else{
            if(!judge_ip(v[0])) err++;
            else{
                int first = stoi(v[0].substr(0,v[0].find_first_of('.')));
                if(is_private(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;
}
全部评论
由示例2可以看出来,这道题对于类似于【0.*.*.*】和【127.*.*.*】的IP地址,即使掩码不符合规范也不能归于不合法,即只要有出现不属于a,b,c,d,e类但是又满足judge_ip的IP就完全不考虑,包括掩码也不再判断。所以这段代码还要加一个这样的判断:如果满足judge_ip但是is_ignore, 就直接continue。
13 回复 分享
发布于 2021-11-07 21:01
主函数里面判断掩码的那个条件需要再加一个first != 127,也就是需要改成if(first!= 127 && (!judgeIp(v[1]) || isMask(v[1])))这样就可以了,要不然第八个样例通过不了。因为题目说了,对于127.*这种事不需要考虑的, 如果不写的活,就会多计算一次错误的数目
12 回复 分享
发布于 2022-01-21 22:28
你这个都跑不通,为啥还是点赞最多的?赶紧修一下Bug吧,丢人啊,误导别人!
9 回复 分享
发布于 2022-07-01 12:01
需要添加这一条语句才能通过所有案例 int first = stoi(v[0].substr(0, v[0].find_first_of('.'))); if (first == 127 || first == 0) continue;
4 回复 分享
发布于 2022-06-04 08:39
我在8/10的时候没通过,明明手算错误掩码的数量是14,答案确实13 这是怎么回事嘞?
3 回复 分享
发布于 2022-05-05 02:31
更正后的代码: #include<iostream> #include<string> #include<sstream> #include<vector> using namespace std; bool judge_ip(string ip) { int j = 0; istringstream iss(ip); string seg; while (getline(iss, seg, '.')) if (++j > 4 || seg.empty() || stoi(seg) > 255) return false; return j == 4; } bool is_private(string ip) { istringstream iss(ip); string seg; vector<int> v; while (getline(iss, seg, '.')) v.push_back(stoi(seg)); if (v[0] == 10) return true; if (v[0] == 172 && (v[1] >= 16 && v[1] <= 31)) return true; if (v[0] == 192 && v[1] == 168) return true; return false; } bool is_mask(string ip) { istringstream iss(ip); string seg; unsigned b = 0; while (getline(iss, seg, '.')) b = (b << 8) + stoi(seg); 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); int first = stoi(v[0].substr(0, v[0].find_first_of('.'))); if (first != 127 && (!judge_ip(v[1]) || !is_mask(v[1]))) err++; else { if (!judge_ip(v[0])) err++; else { if (is_private(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; }</string></int></vector></sstream></string></iostream>
2 回复 分享
发布于 2023-09-02 22:08 广东
10.70.44.68.~255.255.255.0 这样的IP地址,没校验出来
2 回复 分享
发布于 2021-06-14 18:58
掩码要是111100001111000这种形式怎么办 取反加一再减一与之后还是0
2 回复 分享
发布于 2020-12-03 22:37
需要增加一句: (类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时可以忽略) if(first==0||first==127);
1 回复 分享
发布于 2022-11-28 19:00 上海
我发现用C++做简单和入门的不容易,因为相比其他语言少了些函数,但是这种困难的题目能调用的函数不多,考察自己构造类型的,C++写多了很容易
1 回复 分享
发布于 2022-06-19 23:47
题目中没有说子网掩码非法,ip就不用校验了吧?
点赞 回复 分享
发布于 06-05 15:20 山东
b = ~b + 1; // 假设b=11110000, 那么取反再加1为(00001111 + 1),为2个幂次方. 所以只有“前位位连续1, 后面位连续0的数”取反加1才为2的幂次方 if((b & (b-1)) == 0) return true; // 而只有”2的幂次方“ 与 “2的幂次方-1” 才为0. 因为2^n = 100...00, 2^n-1 = 011..11.
点赞 回复 分享
发布于 2023-04-28 14:22 浙江
判断掩码写到else if里,然后先判断前面的ip是否为127或0,如果是,则continue;否则err++
点赞 回复 分享
发布于 2022-12-20 09:06 浙江
255.0.15.0掩码是这样的,提交测试不通过,提交认为是正常掩码
点赞 回复 分享
发布于 2022-11-14 00:28 河南
用个用例,一共40组。结果标准答案里面ABCDE类的加错误类的一共只有39组。。。 直接无语,答案把剩下的一组吞了
点赞 回复 分享
发布于 2022-10-27 19:50 浙江
127开头的没过滤掉
点赞 回复 分享
发布于 2022-07-31 09:24
225.240.129.203~255.110.255.255 183.181.49.4~255.0.0.0 172.177.113.45~255.0.0.0 176.134.46.246~255.0.0.0 153.63.21.56~255.255.58.255 23.135.167.228~255.0.0.0 204.58.47.149~255.0.0.0 113.33.181.46~255.255.255.0 73.245.52.119~255.255.154.0 23.214.47.71~255.0.0.0 139.124.188.91~255.255.255.100 142.94.192.197~255.0.0.0 53.173.252.202~255.0.0.0 127.201.56.50~255.255.111.255 118.251.84.111~255.0.0.0 130.27.73.170~255.0.0.0 253.237.54.56~255.86.0.0 64.189.222.111~255.255.255.139 148.77.44.147~255.0.0.0 59.213.5.253~255.255.0.0 3.52.119.131~255.255.0.0 213.208.164.145~255.255.0.0 24.22.21.206~255.255.90.255 89.43.34.31~255.0.0.0 9.64.214.75~255.0.0.0 110.156.20.173~255.153.0.0 71.183.242.53~255.255.0.0 119.152.129.100~255.0.0.0 38.187.119.201~255.0.0.0 73.81.221.180~255.255.255.255 73.198.13.199~255.0.15.0 99.42.142.145~255.255.255.0 196.121.115.160~255.0.0.0 226.30.29.206~255.0.0.0 244.248.31.171~255.255.255.255 59.116.159.246~255.0.0.0 121.124.37.157~255.0.0.226 103.42.94.71~255.255.0.0 125.88.217.249~255.255.74.255 73.44.250.101~255.255.255.0 用你这个代码,这个用例没过,题目TM的有问题,怎么写都不能全过。
点赞 回复 分享
发布于 2022-06-30 17:01
这是什么牛马==
点赞 回复 分享
发布于 2022-05-07 17:25
对于is_mask函数,在while循环中,每次读入一个.前面的数后右左移8位,在读下一个.前的数时,先左移8位在加这个数,这样子做不就剩下判断最后的8位是否为前面1后面0了,如果在第二个.前面的数出现00111111,每次读入8位又左移不就被覆盖了吗
点赞 回复 分享
发布于 2021-04-11 18:38
针不戳
点赞 回复 分享
发布于 2021-01-15 22:26

相关推荐

用户64975461947315:这不很正常吗,2个月开实习证明,这个薪资也还算合理,深圳Java好多150不包吃不包住呢,而且也提前和你说了没有转正机会,现在贼多牛马公司骗你说毕业转正,你辛辛苦苦干了半年拿到毕业证,后面和你说没hc了😂
点赞 评论 收藏
分享
评论
117
10
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务