题解 | #识别有效的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行,真的是屎山代码了==
