问题概要
请解析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均为非法子网掩码)
注意:
- 类似于【0...】和【127...】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时请忽略
- 私有IP地址和A,B,C,D,E类地址是不冲突的
对应牛客网HJ18 识别有效的IP地址和掩码并进行分类统计
思路分析
本题逻辑倒没什么特别复杂的,重点就是模拟用户输入和划分类型的过程。
不过值得注意的是,在划分类型时,需要注意无效IP和错误IP的判断时机,我最初就是因为没能在判断错误IP之前先过滤掉无效IP,导致两者数量有一定重叠,以至于错误提交了很多次。(下面我会附上我的提交记录,也算是提供一个负面案例了)
代码实现
#include <stdio.h>
#include <stdlib.h>// 判断掩码是否合法 0 错误, 1 正确
int is_valid_mask(const char* mask) {unsigned int m[4];// 读取掩码,并分成4个数字if (sscanf(mask, "%u.%u.%u.%u", &m[0], &m[1], &m[2], &m[3]) != 4) {return 0; // 掩码不合法,返回错误}// 将掩码的四个部分组合成一个32位整数unsigned int num = (m[0] << 24 | m[1] << 16 | m[2] << 8 | m[3]);if (num == 0 ||num == 0xFFFFFFFF) return 0; // 若全为0或全为1,返回错误// 一个标识,标记发现的第一个为0的位int first_zero_found = 0;for (int i = 31; i >= 0; i--) {if (!first_zero_found && !(num & (1 << i))) {// 若还没有找到0,且当前位为0first_zero_found = 1;} else if (first_zero_found && (num & (1 << i))) {// 若前面已有0,而当前位为1,证明掩码中0和1是不连续的,不合法return 0;}}return 1;
}int is_private(unsigned int ip) {unsigned int ip1 = (ip >> 24) & 0xFF;unsigned int ip2 = (ip >> 16) & 0xFF;return (ip1 == 10 || (ip1 == 172 && ip2 >= 16 && ip2 <= 31) || (ip1 == 192 &&ip2 == 168));
}int main() {char line[100];int counts[7] = { 0 }; // A,B,C,D,E,error,privatewhile (fgets(line, sizeof(line), stdin)) {char ip[20], mask[20];// 分隔ip和掩码,并分别存储到数组中。若分割后发现不止ip和mask这两个,证明不合法,error+1if (sscanf(line, "%[^~]~%s", ip, mask) != 2) {counts[5]++;continue;}// 把ip和掩码的每一段数字都存进数组中,若不合法,error+1unsigned int ip_parts[4];unsigned int mask_parts[4];if (sscanf(ip, "%u.%u.%u.%u", &ip_parts[0], &ip_parts[1], &ip_parts[2],&ip_parts[3]) != 4 ||sscanf(mask, "%u.%u.%u.%u", &mask_parts[0], &mask_parts[1], &mask_parts[2],&mask_parts[3]) != 4) {counts[5]++;continue;}unsigned int ip_num = (ip_parts[0] << 24) | (ip_parts[1] << 16) |(ip_parts[2] << 8) | ip_parts[3];unsigned int first_octet = ip_parts[0];// 若第一部分是0或127,忽略if (first_octet == 0 || first_octet == 127) continue;if (!is_valid_mask(mask)) {counts[5]++;continue;}// 判断是否是私有IPif (is_private(ip_num)) {counts[6]++;}if (first_octet >= 1 && first_octet <= 126) {counts[0]++;} else if (first_octet >= 128 && first_octet <= 191) {counts[1]++;} else if (first_octet >= 192 && first_octet <= 223) {counts[2]++;} else if (first_octet >= 224 && first_octet <= 239) {counts[3]++;} else if (first_octet >= 240 && first_octet <= 255) {counts[4]++;} else {counts[5]++;}}printf("%d %d %d %d %d %d %d\n", counts[0], counts[1], counts[2], counts[3],counts[4], counts[5], counts[6]);return 0;
}
注
因为这个代码主要是模拟的过程,所以逻辑并不复杂。但像我那样因为粗心大意,导致很多次错误提交的行为,也足以让人引以为戒了。
希望本文能对您有所帮助。
感谢阅读!