题解 | #识别有效的IP地址和掩码并进行分类统计#
识别有效的IP地址和掩码并进行分类统计
https://www.nowcoder.com/practice/de538edd6f7e4bc3a5689723a7435682
#include <stdio.h> #include <string.h> struct IPType { int Anum; int Bnum; int Cnum; int Dnum; int Enum; int errornum; int privatenum; }; int CalculateType(char typestr[2],int update[7]) { for(int i=0;i<2;i++) { switch (typestr[i]) { case 'A':update[0]=1;break; case 'B':update[1]=1;break; case 'C':update[2]=1;break; case 'D':update[3]=1;break; case 'E':update[4]=1;break; case 'e':update[5]=1;break; case 'p':update[6]=1;break; default: break; } } return update[7]; } char ReturnIPType(int ip[4]) { if(ip[0]<=126 ) { if(ip[0]==0) return 'N'; if(ip[0]==10) return 'p'; else return 'A'; } else if (ip[0]<=191) { if(ip[0]==127) return 'N'; if(ip[0]==172&&ip[1]>=16&&ip[1]<=31) return 'p'; else return 'B'; } else if (ip[0]<=223) { if(ip[0]==192&&ip[1]==168) return 'p'; else return 'C'; } else if (ip[0]<=239) { return 'D'; } else if (ip[0]>239) { return 'E'; } return 'N';//N代表忽略 } int IsSubMask(unsigned int mask) { if(mask==0xFFFFFFFF||mask==0x00000000) return 0; //0xFFFFFFFF代表全1 //假设0xFFFF0000是待测Mask,则~Mask=0x0000FFFF,~Mask+1=0x00010000,此为2^8 //按照这种方法计算只需要计算(~Mask)&(~Mask+1)==0,就可以知道是从开头连续的1了 //或者直接判断(Mask-1)|(Mask)==0xFFFFFFFF(e.g:11110000-1=11101111) //想法来源CSDN 作者shinezhang86:http://t.csdnimg.cn/DLbN5 if(((mask-1)|(mask))==0xFFFFFFFF) return 1; return 0; } int main() { char str[666][32]; int num=-1; do { num++; }while(scanf("%s",&str[num])!=EOF); struct IPType ipType={0}; for(int i=0;i<num;i++)//num是总行数,最后一行是回车所以不用取到 { int errsum=ipType.errornum; int dotlct[3]; int dotnum=-1; int tildelct=strlen(str[i]); char iptype[2]={'U'}; for(int j=0;j<strlen(str[i]);j++) { if(str[i][j]=='.'&&++dotnum<3) //判断出地址的三个.的位置 { dotlct[dotnum]=j; //判断.与.相隔需大于0位且小于3位 if(dotnum>0) { if(dotlct[dotnum]-dotlct[dotnum-1]>4||dotlct[dotnum]-dotlct[dotnum-1]<2) { ipType.errornum++; break; } } else //每个地址第一个数字段需大于0位且小于3位 { if(j<tildelct?(dotlct[0]>3||dotlct[0]<1):(dotlct[0]-tildelct<2||dotlct[0]-tildelct>4)) { ipType.errornum++; break; } } } if(str[i][j]=='~')//先判断出~的位置,记为j,两个地址以~相隔分开判断 { if(j-dotlct[2]>4||j-dotlct[2]<2) { ipType.errornum++; break; } //判断子网掩码长度符合要求 if(strlen(str[i])-j>7&&strlen(str[i])-j<17) { int ip[4]={-1,-1,-1,-1}; int ip_k=0;//k保存为第几个字段 for(int l=0;l<j&&ip_k<4;l=dotlct[ip_k++]+1)//当前数字下标从起始位置dotlct[k-1]+1到dotlct[k] { char tmp[4]={'\0'};//整合保存当前数字以便转换为int for(int m=0;(ip_k<3)?l+m<dotlct[ip_k]:l+m<j;m++)//判断l(初始位置)+m(第几个数字)<下一个.的位置或当是第四个数字段时<~的位置 { tmp[m]=str[i][l+m]; } //以上得到了一至三个数字的字符串,先转换成int型赋值给ip ip[ip_k]=atoi(tmp); //判断数字属于0~255 if((ip[ip_k]>=0)?( (ip[ip_k]<256)?(0):(1) ):(1)) { ipType.errornum++; break; } } if(ipType.errornum>errsum) break;//识别IP地址有错误后续跳过 else { dotnum=-1;//重置三个.给子网掩码 tildelct=j;//记下波浪号的位置 } //再此验证IPtype iptype[0]=ReturnIPType(ip); //printf("%c",iptype); //私有地址和类地址不冲突,所以还需要再进行一次 if(iptype[0]=='p') { switch (ip[0]) { case 10: iptype[1]='A'; break; case 172: iptype[1]='B'; break; case 192: iptype[1]='C'; break; default: break; } } } else { ipType.errornum++; break; } //Ip地址没太大问题的情况来到这里,此时有j=~的位置,dotnum=0,errsum=ipType.errornum //当ip识别为可以忽略不记时,直接跳过 if(iptype[0]=='N') break; } //这里是不是~且不是.的地方 if(j==strlen(str[i])-1)//来到最后一位 { if(j+1-dotlct[2]>4||j+1-dotlct[2]<2) { ipType.errornum++; break; } int submask[4]={0,0,0,0}; unsigned int mask=0; for(int sm_k=0;sm_k<4;sm_k++) { char tmp[4]={'\0'}; int beginloc=(sm_k>0)?(dotlct[sm_k-1]+1):(tildelct+1); //根据sm_k是第几个数字字段进行自增赋值 for(int l=beginloc;(sm_k<3)?(l<dotlct[sm_k]):(l<=j);l++) { tmp[l-beginloc]=str[i][l]; } submask[sm_k]=atoi(tmp); //判断数字属于0~255 if((submask[sm_k]<0) && (submask[sm_k]>255)) { ipType.errornum++; break; } //利用位运算合并成一个数,传入识别是否从头连续1的函数 else { mask=(mask<<8)+submask[sm_k]; } if(sm_k==3) { if(!IsSubMask(mask)) { ipType.errornum++; break; } } } if(ipType.errornum>errsum) break;//识别IP地址有错误后续跳过 else { //传入之前IP地址返回的字符,识别并计入到结构体中 //printf("correct IP and Mask\n"); int update[7]={0}; update[7]=CalculateType(iptype,update); ipType.Anum+=update[0]; ipType.Bnum+=update[1]; ipType.Cnum+=update[2]; ipType.Dnum+=update[3]; ipType.Enum+=update[4]; ipType.errornum+=update[5]; ipType.privatenum+=update[6]; } } } } printf("%d %d %d %d %d %d %d",ipType.Anum,ipType.Bnum,ipType.Cnum,ipType.Dnum,ipType.Enum,ipType.errornum,ipType.privatenum); return 0; }
写了快300行,真的是屎山代码了==