博主头像

ワクワク

2025/07/26 HJ18 识别IP掩码并分类

描述

在本题中,我们需要处理地址信息,其由 IP 地址和子网掩码组成,这两者均形如"*.*.*.*",由四段数字组成(每一个 ‘*’表示一个数字),每一段的数字均为 0 到 255 之间的一个整数,每段数字之间以点分隔。

我们定义五类 IP 地址: A 类:"1.0.0.0"∼"127.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.254.255.0" 转换拼接得到字符串 11111111 11111110 11111111 00000000,显然不合法;掩码"255.255.255.248" 转换拼接得到字符串 11111111 11111111 11111111 11111000,合法。注意,全为 1 或全为 00的掩码也视为非法。

我们定义错误的 IP 地址和错误的子网掩码为不符合上述定义的 IP 地址和子网掩码。例如,格式错误、数字超出范围等等。 现在,你需要分类统计 A、B、C、D、E 类地址的数量、错误 IP 或错误子网掩码的数量、私有 IP 的数量。 特别地: 类似 "0.*.*.*" 和 ""127.*.*.*" 的 IP 地址不计入任何类别,也不计入非法统计,直接跳过; 一个 IP 既可计入私有 IP,也可计入五类地址之一,二者分别累计。

输入描述:

本题将会给出1≦T≦1000 条地址信息,确切数字未知,您需要一直读取至文件结尾;您也可以参考 牛客网在线判题系统使用帮助 获得更多的使用帮助。每条地址信息描述如下: 每行输入一个"*.*.*.*" 形式的 IP 地址和一个"*.*.*.*" 形式的子网掩码,中间用波浪线(∼)分隔。保证‘*’ 要么为空,要么是一个 0 到 255 间的整数。

输出描述:

在一行上输出七个整数,分别代表 A 类地址数、B 类地址数、C 类地址数、D 类地址数、E 类地址数、错误 IP 或错误子网掩码数、私有 IP 数。

示例1

输入:

10.70.44.68~1.1.1.5
1.0.0.1~255.0.0.0
192.168.0.2~255.255.255.0
19..0.~255.255.255.0

输出:1 0 1 0 0 2 1

说明:

在这个样例中:

  • 第一条地址信息:掩码非法;
  • 第二条地址信息:IP 格式和掩码均合法,属于 A 类;
  • 第三条地址信息:IP 格式和掩码均合法,属于 C 类私有地址;
  • 第四条地址信息:IP 格式非法。

统计得到 11 个 A 类,00 个 B 类,11 个 C 类,00 个 D 类,00 个 E 类,22 个错误条目,11 个私有地址。

示例2

输入:

0.201.56.50~255.255.255.0
127.201.56.50~255.255.111.255

输出:0 0 0 0 0 0 0

说明:在这个样例中,两条地址信息均属于上方提示中提到的特殊 IP 地址,不需要处理,直接跳过。特别需要注意地,第二条地址的子网掩码是非法的。但是因为该条为特殊 IP 地址,此优先级更高,所以不进入统计。

思路

以4位IP数组和4位Mask数组记录IP和掩码

  1. 排除0和127开头IP

    1. 用状态码标记为不计数状态
  2. 掩码格式检查

    1. 排除首位非255情况
    2. 用状态码计数255和0的出现次数,排除全255、全0情况
    3. 十进制转二进制
    4. 二进制掩码格式为先1后0,用状态码记录是否有0出现,若出现过0且掩码出现1,则非法
  3. IP格式检查

    1. 0-255范围
  4. 分类

    1. 按IP首位分类五类IP,对应分类计数+1
    2. 在五类IP分类中标注特定开头的私有IP,私有IP+1,对应分类+1

题解

#include <stdio.h>

int mask_filter(int mask[4]);

int mask_filter(int mask[4]) {
    //设置十进制临时掩码temp以及二进制临时掩码temp_mask[7]
    int temp;
    int temp_mask[7];
    //设置二进制数状态量k,初始值为-1,当出现0时,修改状态量为1
    int k = -1;
    //计数掩码为0和掩码为255的情况
    int status_0 = 0;
    int status_255 = 0;
    //首位不为255,则非法
    if (mask[0] != 255) {
        return -1;
    }
    //遍历,统计掩码为0和掩码为255情况
    for (int i = 0; i < 4; i++) {
        if (mask[i] == 255) {
            status_255++;
        }
        else if (mask[i] == 0) {
            status_0++;
        }
        //将临时掩码转换为二进制
        temp = mask[i];
        for (int j = 7; j >= 0; j--) {
            temp_mask[j] = temp%2;
            temp /= 2;
        }
        //掩码为0,则状态量k修改为1,若出现掩码0状态量k1的情况,就表示1之间插入了0,非法
        for (int j = 0; j < 8; j++) {
            if (temp_mask[j] == 1) {
                if (k == 1) {
                    return -1;
                }
            }
            else if (temp_mask[j] == 0) {
                k = 1;
            }
        }
    }
    //掩码全为255或全为0,非法
    if (status_0 == 4) {
        return -1;
    }
    else if (status_255 == 4) {
        return -1;
    }
    非法情况均排除
    return 1;
}

//IP不在0~255之间,非法
int ip_filter(int* ip) {
    for (int i = 0; i < 4; i++) {
        if (ip[i] < 0 || ip[i] > 255) {
            return -1;
        }
    }
    return 1;
}

int main() {
    //初始化ip和掩码数组
    int ip[4] = {0}, mask[4] = {0};
    int A_num = 0, B_num = 0, C_num = 0, D_num = 0, E_num = 0, error_num = 0,pri_num = 0;
    //skip为1时表示此IP不计数
    int skip = 0;
    char str[1024];
    //按行赋值str
    while (fgets(str, sizeof(str), stdin) != NULL) {
        //将'\n'换行符替换为'\0',使后面内容无效
        str[strcspn(str, "\n")] = '\0';
        //开头为127.或0.时不计数
        if ((str[0] == '1') && (str[1] == '2')&& (str[2] == '7')&& (str[3] == '.')) {
            skip = 1;
        }
        else if ((str[0] == '0') && (str[1] == '.')) {
            skip = 1;
        }
        //在输入内容格式标准无空缺,IP计数情况下
        if ((sscanf(str, "%d.%d.%d.%d~%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3],&mask[0], &mask[1], &mask[2], &mask[3]) == 8) && skip != 1) {
            //掩码、IP格式判断
            if (mask_filter(mask) == -1) {
                error_num++;
            } else if (ip_filter(ip) == -1) {
                error_num++;
            } 
            //IP分类划分
            else {
                if (ip[0] >= 1 && ip[0] <= 127) {
                    if (ip[0] == 10) {
                        pri_num++;
                        A_num++;
                    } else {
                        A_num++;
                    }
                } else if (ip[0] >= 128 && ip[0] <= 191) {
                    if (ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) {
                        pri_num++;
                        B_num++;
                    } else {
                        B_num++;
                    }
                } else if (ip[0] >= 192 && ip[0] <= 223) {
                    if (ip[0] == 192 && ip[1] == 168) {
                        pri_num++;
                        C_num++;
                    } else {
                        C_num++;
                    }
                } else if (ip[0] >= 224 && ip[0] <= 239) {
                    D_num++;
                } else if (ip[0] >= 240 && ip[0] <= 255) {
                    E_num++;
                }
            }
        } 
        //输入IP格式非法但计数情况
        else if (skip != 1) {
            error_num++;
        }
        skip = 0;
    }
    printf("%d %d %d %d %d %d %d", A_num, B_num, C_num, D_num, E_num, error_num,pri_num);
    return 0;
}


2025/07/26 HJ18 识别IP掩码并分类
https://blog.minliny.com/index.php/archives/6/
本文作者 Minliny
发布时间 2025-07-26
许可协议 CC BY-NC-SA 4.0
发表新评论