首页 > 试题广场 >

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

[编程题]识别有效的IP地址和掩码并进行分类统计
  • 热度指数:356334 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解

请解析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.0239.255.255.255;

E类地址从240.0.0.0255.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均为非法子网掩码)

注意:
1. 类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时请忽略
2. 私有IP地址和A,B,C,D,E类地址是不冲突的



输入描述:

多行字符串。每行一个IP地址和掩码,用~隔开。

请参考帖子https://www.nowcoder.com/discuss/276处理循环输入的问题。


输出描述:

统计A、B、C、D、E、错误IP地址或错误掩码、私有IP的个数,之间以空格隔开。

示例1

输入

10.70.44.68~255.254.255.0
1.0.0.1~255.0.0.0
192.168.0.2~255.255.255.0
19..0.~255.255.255.0
127.69.131.137~255.70.255.255

输出

1 0 1 0 0 2 1

说明

10.70.44.68~255.254.255.0的子网掩码非法,19..0.~255.255.255.0的IP地址非法,所以错误IP地址或错误掩码的计数为2;
1.0.0.1~255.0.0.0是无误的A类地址;
192.168.0.2~255.255.255.0是无误的C类地址且是私有IP;
127.69.131.137~255.70.255.255 计数忽略
所以最终的结果为1 0 1 0 0 2 1        
示例2

输入

0.201.56.50~255.255.111.255
127.201.56.50~255.255.111.255

输出

0 0 0 0 0 2 0

说明

类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时请忽略         
#include <stdio.h>

typedef struct ip{
    int A;
    int B;
    int C;
    int D;
    int E;
    int error;
    int privacy;
} IP;

int main(){
    IP ipv4={0};
    char str[200];
    int ip[4]={0},mask[4]={0};
    int count;
    
    while(scanf("%s",str) !=EOF){
        count=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]);

        if(ip[0]==0 || ip[0]==127){
            continue;
        }
        if(count != 8){
            ipv4.error++;
            continue;
        }

        int mask32 = (mask[0] << 24)+(mask[1] << 16) +(mask[2]<<8)+mask[3];
        if(((~mask32+1)& ~mask32) || ! ~mask32){
            
            ipv4.error++;
            continue;
        }

        if(ip[0] >=1 && ip[0]<=126){
            ipv4.A++;
        }
        else if (ip[0]>=128 && ip[0] <=191) {
            ipv4.B++;
        
        }
        else if (ip[0]>=192 && ip[0] <= 223) {
            ipv4.C++;
        
        }
        else if (ip[0] >= 224 && ip[0] <=239) {
            ipv4.D++;
        
        }
        else {
            ipv4.E++;
        }
        if(ip[0]==10 || (ip[0]==172&&ip[1]>= 16&&ip[1]<=31) || (ip[0]==192 &&ip[1]==168)){
            ipv4.privacy++;
        }
    }
    printf("%d %d %d %d %d %d %d",ipv4.A,ipv4.B,ipv4.C,ipv4.D,ipv4.E,ipv4.error,ipv4.privacy);
    return 0;
}

发表于 2024-09-02 20:20:49 回复(0)
平台的程序有问题,我这个程序输出是正确的
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int g_ipa = 0;
int g_ipb = 0;
int g_ipc = 0;
int g_ipd = 0;
int g_ipe = 0;
int g_err = 0;
// int g_mask_err = 0;
int g_ip_pri = 0;
// int g_ipe = 0;

unsigned int ipa_min,ipa_max;
unsigned int ipb_min,ipb_max;
unsigned int ipc_min,ipc_max;
unsigned int ipd_min,ipd_max;
unsigned int ipe_min,ipe_max;
unsigned int ipp1_min,ipp1_max;
unsigned int ipp2_min,ipp2_max;
unsigned int ipp3_min,ipp3_max;


unsigned int ipstr_to_u32(char *ip)
{
    unsigned int ipa = 0;
    int tmp[4];
    int cnt = sscanf(ip,"%d.%d.%d.%d",&tmp[0],&tmp[1],&tmp[2],&tmp[3]);
    if(cnt != 4)   //匹配次数
    {
        return 0;
    }
    ipa = ipa | (tmp[0] << 24);
    ipa = ipa | (tmp[1] << 16);
    ipa = ipa | (tmp[2] << 8);
    ipa = ipa | (tmp[3] );
    return ipa;
}   

//return 0 :ip err
int check_ip_valide(char *ip)
{
    int ipa = ipstr_to_u32(ip);
    if(ipa == 0 || strlen(ip) < 7)
    {
        return 0;
    }
    return ipa;

}
#define bitset(x,p) ((x >> p) & 0x1)
#define u32tobits(x,buf) for(int __i = 0;__i<32;__i++) buf[32-__i-1]= bitset(x,__i)==1?'1':'0';
int check_mask_valid(char *mask)
{
    unsigned int m = ipstr_to_u32(mask);
    char maskstr[33] = {0};
    u32tobits(m, maskstr);
    // printf("mask str %s\n",maskstr);
    if(strstr(maskstr,"01") || m == 0xffffffff || m == 0)   //需要返回来
    {
        // printf("mask error %s\n",mask);
        return 0;
    }

    // printf("mask %s %u ->%s ok\n",mask,m, maskstr);
    return 1;
}

int check_line(char *line)
{
    char *p,*ph = line;
    char *ip = line;
    char *mask ;
    unsigned int ipi;
    
    p = strchr(ph,'~');
    if(!p){
        // g_err++;
        return 0;
    }
    *p = '\0';
    mask = p+1;
    ipi = check_ip_valide(ip);
    if(0 == ipi || 0 == check_mask_valid(mask))
    {
        g_err++;
        // printf("%s %s error %d\n",ip,mask,g_err);
        return 0;
    }else{
        if(ipi>= ipa_min && ipi <= ipa_max)
        {
            g_ipa++;
        }else if(ipi>= ipb_min && ipi <= ipb_max)
        {
            g_ipb++;
        }else if(ipi >= ipc_min && ipi <= ipc_max)
        {
            g_ipc++;
        }else if(ipi >= ipd_min && ipi <= ipd_max)
        {
            g_ipd++;
        }else if(ipi >= ipe_min && ipi <= ipe_max)
        {
            g_ipe++;
        }
        if((ipi >= ipp1_min && ipi <= ipp1_max) || (ipi >= ipp2_min && ipi <= ipp2_max) || (ipi >= ipp3_min && ipi <= ipp3_max))
        {
            g_ip_pri++;
        }
    }
    return 0;
}

void init_iptype()
{
    ipa_min = ipstr_to_u32("1.0.0.0");
    ipa_max = ipstr_to_u32("126.255.255.255");
    ipb_min = ipstr_to_u32("128.0.0.0");
    ipb_max = ipstr_to_u32("191.255.255.255");

    ipc_min = ipstr_to_u32("192.0.0.0");
    ipc_max = ipstr_to_u32("223.255.255.255");

    ipd_min = ipstr_to_u32("224.0.0.0");
    ipd_max = ipstr_to_u32("239.255.255.255");

    ipe_min = ipstr_to_u32("240.0.0.0");
    ipe_max = ipstr_to_u32("255.255.255.255");

    ipp1_min = ipstr_to_u32("10.0.0.0");
    ipp1_max = ipstr_to_u32("10.255.255.255");

    ipp2_min = ipstr_to_u32("172.16.0.0");
    ipp2_max = ipstr_to_u32("172.31.255.255");
    ipp3_min = ipstr_to_u32("192.168.0.0");
    ipp3_max = ipstr_to_u32("192.168.255.255");
}
//输入一行都要做一次校验
int main() {
    char line[48];
    init_iptype();
    while(scanf("%s",line) != EOF)
    {
        check_line(line);
        memset(line,0,sizeof(line));
    }
    printf("%d %d %d %d %d %d %d",g_ipa,g_ipb,g_ipc,g_ipd,g_ipe,g_err,g_ip_pri);
    return 0;
}


发表于 2024-07-30 15:06:26 回复(0)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//本题有个学习点就是如何循环输入
//自测都可以过但是提交提示段错误

//IP地址检测
int legalIP(char* a)
{
    int i,j=1;
    int num[4]={0};
    num[0] =  atoi(&a[0]);
    for(i=0; i<=strlen(a); i++)
    {
        if(a[i] == '.')
        {
            if(a[i+1] >= '0' && a[i+1] <= '9')
           {
            num[j] = atoi(&a[i+1]);
            j++;
           }
        }
    }
        if(j == 4 && (num[0]>=1 && num[0]<=255) && (num[1]>=0 && num[0]<=255)  && (num[2]>=0 && num[0]<=255) && (num[3]>=0 && num[0]<=255))
        {
            return 1;
        }
        else {
            return 0;
        } 
}
//三位数掩码是否合法
int legalMask2(int a)
{
    int i=255;
    while(i >= 0)
    {
        if(a == (i & 255))
        {           
            return 1;
        }
        i = i << 1;
    }
    return 0;
}
//掩码是否合法
int legalMask(char* a)
{
    int i,j=1;
    int num[4]={0};
    num[0] = atoi(&a[0]);
    for(i=0; i<=strlen(a); i++)
    {
        if(a[i] == '.')
        {
            if(a[i+1] >= '0' && a[i+1] <= '9')
            {    
                num[j] = atoi(&a[i+1]);
                j++;
            }
        }
    }
    if(j == 4)
    {
        if(num[0] == 255)
        {
            if(num[1] == 255)
            {
                if(num[2] == 255)
                {
                    if(legalMask2(num[3]) && num[3] != 255)
                        return 1;
                    else
                        return 0;
                }
                else if(legalMask2(num[2]) && num[3] == 0)
                {
                    return 1;
                }
                else {
                    return 0;
                }
            }
            else if(legalMask2(num[1]) && num[2] == 0 && num[3] == 0)
            {
                return 1;
            }
            else {
                return 0;
            }
               
        }
        else if(legalMask2(num[0]) && num[1] == 0 && num[2] == 0 && num[3] == 0 && num[0] != 0)
        {
            return 1;
        }
        else {
            return 0;
        }

    }
    else {
        return 0;
    }
}

int main() {
    char input[1000][40]={0};
    char IP[1000][20]={0},Mask[1000][20]={0};
    int i=0,j=0;
    int num[7]={0};
    //直接用for循环输入不进来
    while(scanf("%s",&input[i][0]) != EOF)
    {
        for(j=0; j<=40; j++)
        {
            if(input[i][j] == '~')
            {
                input[i][j] = '\0';
                strcpy(&IP[i][0], &input[i][0]);
                strcpy(&Mask[i][0], &input[i][j+1]);
                break;
            }
        }
        if(legalIP(&IP[i][0]) && legalMask(&Mask[i][0]))
        {
            if(atoi(&IP[i][0]) >=1 && atoi(&IP[i][0]) <=126)
            num[0] += 1;
            else if(atoi(&IP[i][0]) >=128 && atoi(&IP[i][0]) <=191)
            num[1] += 1;
            else if(atoi(&IP[i][0]) >=192 && atoi(&IP[i][0]) <=223)
            num[2] += 1;
            else if(atoi(&IP[i][0]) >=224 && atoi(&IP[i][0]) <=239)
            num[3] += 1;
            else if(atoi(&IP[i][0]) >=240 && atoi(&IP[i][0]) <=255)
            num[4] += 1;

            if(atoi(&IP[i][0]) == 10)
            num[6] += 1;
            if(atoi(&IP[i][0]) == 172 && (atoi(&IP[i][4]) >=16 && atoi(&IP[i][4]) <=31))
            num[6] += 1;
            if(atoi(&IP[i][0]) == 192 && atoi(&IP[i][4]) == 168)
            num[6] += 1;
        }
        else if(atoi(&IP[i][0]) == 0 || atoi(&IP[i][0]) == 127)
        i = i;
        else {
            num[5] += 1;
        }
    i++;
    }
    printf("%d %d %d %d %d %d %d",num[0],num[1],num[2],num[3],num[4],num[5],num[6]);
    return 0;
}

发表于 2024-04-28 20:30:33 回复(0)
c
#include <stdio.h>
#include <string.h>
int check(int n)
{
    int flag = 0, i, b = 7;
    int a[8];
    memset(a, 0, 32);
    while(n)
    {
        a[b--] = n % 2;
        n /= 2;
    }
    for(i = 0; i < 8; i++)
    {
        if(a[i] == 0)
            flag = 1;
        else if(a[i] == 1 && flag)
            return 1;
    }
    return 0;  
}
int main() 
{
    int i, j, n, b[7], flag = 0;
    char ch;
    int a[1000][8];
    memset(a, -1, 8000);
    memset(b, 0, 28);
    for(i = 0; 1; i++)
    {
        for(j = 0; j < 8; j++)
        {
            scanf("%d", &a[i][j]);
            ch = getchar();
        }
        if(ch == EOF)
            break;
    }
    n = i;
    for(i = 0; i < n; i++)
    {
        if(a[i][0] == 0 || a[i][0] == 127)
            continue;
        if((a[i][4] == 0 && a[i][5] == 0 && a[i][6] == 0 && a[i][7] == 0) || (a[i][4] == 255 && a[i][5] == 255 && a[i][6] == 255 && a[i][7] == 255))
        {
            b[5]++;
            continue;
        }
        for(j = 0; j < 8; j++)
        {
            if(a[i][j] == -1)
            {
                flag = 1;
                b[5]++;
                break;
            }
        }
        for(j = 4; j < 8; j++)
        {
            if(a[i][j] < 255)
            {
                if(check(a[i][j]))
                {
                    flag = 1;
                    b[5]++;
                }
                else 
                {
                    for(int k = j + 1; k < 8; k++)
                        if(a[i][k] != 0)
                        {
                            flag = 1;
                            b[5]++;
                            break;
                        }
                }
                if(flag)
                    break;
            }
        }
        if(flag)
        {
            flag = 0;
            continue;
        }
        else
        {
            if(a[i][0] >= 1 && a[i][0] <= 126)
            {
                b[0]++;
                if(a[i][0] == 10)
                    b[6]++;
            }
            else if(a[i][0] >= 128 && a[i][0] <= 191)
            {
                b[1]++;
                if(a[i][0] == 172 && (a[i][1] >= 16 && a[i][1] <= 31))
                    b[6]++;
            }
            else if(a[i][0] >= 192 && a[i][0] <= 223)
            {
                b[2]++;
                if(a[i][0] == 192 && a[i][1] == 168)
                    b[6]++;
            }
            else if(a[i][0] >= 224 && a[i][0] <= 239)
                b[3]++;
            else if(a[i][0] >= 240 && a[i][0] <= 255)
                b[4]++;
        }
    }
    for(i = 0; i < 7; i++)
        printf("%d ", b[i]);
    printf("\n");
    return 0;
}


发表于 2024-03-07 22:40:06 回复(0)
#include <stdio.h>
//将输入的字符串转换成整型存入数组中,方便判断
void change(char* str,int arr[])
{
    char* start=str;
    char* end=str;
    int i=0;
    int j =0;
    for(i=0;i<32;i++)
    {
        if(str[i]=='.'||str[i]=='\0'||str[i]=='~')
        {
            if(start==end)//点后接点如19..0.
            {
                arr[0]=1000;
                break;
            }
            for(;start<end;start++)
            {
                arr[j]=arr[j]*10+(int)(*start-'0');
            }
            //printf("%d ",arr[j]);
            start++;
            j++;
        }
        if(str[i]=='\0')
            break;
        end++;
    }
}
//掩码判断
int netmask(int arr[])
{
    unsigned int integerMask = 0;
    //将掩码变成无符号整数
    for (int i = 0; i < 4; i++) 
    {
        integerMask += arr[i+4] << (24 - 8 * i);
        //printf("%u\n",integerMask);
    }
    
    int networkBits = 0;
    int hostBits = 0;
    int isHostBitsStarted = 0;

    for (int i = 31; i >= 0; i--) 
    {
        if ((integerMask>> i) & 1) 
        {
            if (isHostBitsStarted) //有0后又出现1即为错误掩码
            {
                return 0; // 掩码无效:主机位中有1
            }
            networkBits++;
        } 
        else 
        {
            isHostBitsStarted = 1;//开始有0,
            hostBits++;
        }
    }
    if(networkBits ==32||hostBits ==32)//全零或者全1
    {
        return 0;
    }
    return 1;
}
//类型判断
void classfication(int arr[],int output[])
{
    int ret =netmask(arr);
    //printf("%d\n",ret);
    //五类
    if(arr[0]>=1&&arr[0]<=126&&ret ==1)
    {
        output[0]++;
    }
    else if(arr[0]>=128&&arr[0]<=191&&ret ==1)
    {
        output[1]++;    
    }
    else if(arr[0]>=192&&arr[0]<=223&&ret ==1)
    {
        output[2]++;
    }
    else if(arr[0]>=224&&arr[0]<=239&&ret ==1)
    {
        output[3]++;
    }
    else if(arr[0]>=240&&arr[0]<=255&&ret ==1)
    {
        output[4]++;
    }
    else if(arr[0]==0||arr[0]==127);
    else
    {
        output[5]++;
    }
    //私网ip
    if(arr[0]==10&& ret ==1)
    {
        output[6]++;
    }
    else if(arr[0]==172&&arr[1]>=16&&arr[1]<=31&&ret ==1)
    {
        output[6]++;
    }
    else if(arr[0]==192&&arr[1]==168&&ret ==1)
    {
        output[6]++;
    }
}
//输出
void print(int output[])
{
    //printf("\n");
    for(int i=0;i<7;i++)
    {
        printf("%d ",output[i]);
    }
}

int main() {
    char ip[32]={0};
    int output[7]={0}; 
    while(scanf("%s",ip)!=EOF)
    {
        int arr[8]={0};
        change(ip,arr);
        classfication(arr,output);
    }
        print(output);
    return 0;
}

发表于 2023-12-23 11:14:15 回复(0)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* 描述
请解析IP地址和对应的掩码,进行分类识别。要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类。 */



int main()
{
    /* 思路
        输入一行后进行判断统计,然后输入下一行
    */

    char astring[32] = {0};
    int output[7] = {0};

    int length=0;
    long hide;
    int i,l,error=0,n,m=0;
    int number[8];

    /* 循环输入,输入后直接对数据处理,统计 */
    while(fgets(astring,32,stdin)!=NULL)
    {
        length=strlen(astring);
        for(i=0;i<8;i++)
            number[i]=0;
        l=0;
        m=0;
        error = 0;//参数清零

        if(astring[length-1]=='\n'){
            astring[length-1]=0;
            length--;
        }
        
        /* 将ip~掩码字符串拆分放进整数数组 */

        for(n=0;n<8;n++)
        {
            while(astring[l]!='.'&&astring[l]!='~'&&astring[l]!=0)
            {
                if(astring[l]<'0'||astring[l]>'9')
                    error = 1;//ip是否有误
                l++;
            }

            switch(l-m){
                case 3:
                    number[n] += (astring[l-3]-'0')*100;
                case 2:
                    number[n] += (astring[l-2]-'0')*10;
                case 1:
                    number[n] += astring[l-1]-'0';
                    if(number[n]>255)
                        error = 1;//ip是否有误
                    break;
                default:
                    error = 1;//ip是否有误
            }
            l++;
            m=l;
            
        }
        /* 判断子网掩码是否正确 */
        for(i=0;i<4;i++)
        {
            for(n=0;n<7;n++)
            {
                if((number[i+4]&(3<<n))==(1<<n))
                   error = 1;
            }
        }
        
        if ( (!(number[4] & 1) && (number[5] & (1 << 7))) ||
                (!(number[5] & 1) && (number[6] & (1 << 7))) ||
                (!(number[6] & 1) && (number[7] & (1 << 7)))||
                (number[4]==255&&number[5]==255&&number[6]==255&&number[7]==255)||
                (number[4]==0&&number[5]==0&&number[6]==0&&number[7]==0))
                error = 1;
        /* 综合处理判断ip或子网掩码是否正确-注意127和0不考虑 */
        if(error&&number[0]!=127&&number[0]!=0)
        {
            
            output[5]++;
        }
        else
        {
        /* 统计ABCDE和私有ip */
            if(number[0]>=1&&number[0]<=126)
            {
                output[0]++;//a
            }
            else if(number[0]>=128&&number[0]<=191)
            {
                output[1]++;//b
            }
            else if(number[0]>=192&&number[0]<=223)
            {
                output[2]++;//c
            }
            else if(number[0]>=224&&number[0]<=239)
            {
                output[3]++;//d
            }
            else if(number[0]>=240&&number[0]<=255)
            {
                output[4]++;//e
            }

            if((number[0]==10)||
               (number[0]==172&&number[1]>=16&&number[1]<=31)||
               (number[0]==192&&number[1]==168) )
                output[6]++;

        }

    }
    /* 输出 */
    for(i=0;i<6;i++)
            printf("%d ",output[i]);
        printf("%d",output[6]);


}



发表于 2023-11-17 04:37:34 回复(0)
#include <stdio.h>
#include <string.h>
#include <math.h>
#define SIZE 32

int main() {
    char ip_str[SIZE], ips[SIZE], mks[SIZE];
    int IPS[SIZE], MKS[SIZE];
    int A = 0, B = 0, C = 0, D = 0, E = 0, IP_S = 0, ERRO = 0;
    int i = 0, y = 0, IPS_I = 0, MKS_I = 0;

    while (fgets(ip_str, SIZE, stdin) != NULL) {
        i = 0;
        while (ip_str[i] != '~') {
            ips[i] = ip_str[i];
            i++;
        }
        ips[i] = '.';
        ips[i+1] = '\0';
        y = i + 1;
        i = 0;
        while (ip_str[y + i]) {
            mks[i] = ip_str[y + i];
            i++;
        }
        mks[i-1] = '.';
       
        int ips_y=0;
       
        for (int x = 0; x < SIZE; x++) {
           
            if (ips[x] == '.') {
                if(ips[x+1] == '.')
                {
                    ERRO++;
                    goto end;
                }
                else {
                    while(ips_y>0)
                    {                    
                        IPS[IPS_I] += (ips[x-ips_y] - '0')*(pow(10,ips_y-1)) ;
                        ips_y--;
                    }
                }
                ips_y--;
                IPS_I++;
            }
            ips_y++;
        }
        int mks_y=0;
        for (int x = 0; x < SIZE; x++) {
            if (mks[x] == '.') {
                if(mks[x+1] == '.')
                {
                    ERRO++;
                    goto end;
                }
                else{
                    while(mks_y>0)
                    {
                        MKS[MKS_I] += (mks[x-mks_y] - '0')*(pow(10,mks_y-1)) ;
                        mks_y--;
                    }
                }
               
                mks_y--;
                MKS_I++;
            }
            mks_y++;
        }
        if(IPS[0]>=1&&IPS[0]<=126&&IPS[1]<=255&&IPS[2]<=255&&IPS[3]<=255&&IPS[1]>=0&&IPS[2]>=0&&IPS[3]>=0)
        {
            if(255-MKS[0]==0)
            {
                 if(255-MKS[1]==0||255-MKS[1]==255)
                 {
                    if(255-MKS[2]==0||255-MKS[2]==255)
                    {
                        if(255-MKS[3]==255)
                        {
                             A++;
                            if(IPS[0]==10)
                            {
                                IP_S++;
                            }
                        }
                        else ERRO++;
                    }
                    else ERRO++;
                 }
                 else ERRO++;
            }
            else ERRO++;
           
        }
        else if(IPS[0]>=128&&IPS[0]<=191&&IPS[1]<=255&&IPS[2]<=255&&IPS[3]<=255&&IPS[1]>=0&&IPS[2]>=0&&IPS[3]>=0)
        {
            if(255-MKS[0]==0)
            {
                 if(255-MKS[1]==0||255-MKS[1]==255)
                 {
                    if(255-MKS[2]==0||255-MKS[2]==255)
                    {
                        if(255-MKS[3]==255)
                        {
                             B++;
                            if(IPS[0]==172&&IPS[1]>=16&&IPS[1]<=31)
                            {
                                IP_S++;
                            }
                        }
                        else ERRO++;
                    }
                    else ERRO++;
                 }
                 else ERRO++;
            }
            else ERRO++;
           
        }
        else if(IPS[0]>=192&&IPS[0]<=223&&IPS[1]>=0&&IPS[2]<=255&&IPS[3]<=255&&IPS[1]<=255&&IPS[2]>=0&&IPS[3]>=0)
        {
            if(255-MKS[0]==0)
            {
                 if(255-MKS[1]==0||255-MKS[1]==255)
                 {
                    if(255-MKS[2]==0||255-MKS[2]==255)
                    {
                        if(255-MKS[3]==255)
                        {
                            C++;
                            if(IPS[0]==192&&IPS[1]==168)
                            {
                                IP_S++;
                            }
                        }
                        else ERRO++;
                    }
                    else ERRO++;
                 }
                 else ERRO++;
            }
            else ERRO++;
        }
        else if(IPS[0]>=224&&IPS[0]<=239&&IPS[1]<=255&&IPS[2]<=255&&IPS[3]<=255&&IPS[1]>=0&&IPS[2]>=0&&IPS[3]>=0)
        {
             if(255-MKS[0]==0)
            {
                 if(255-MKS[1]==0||255-MKS[1]==255)
                 {
                    if(255-MKS[2]==0||255-MKS[2]==255)
                    {
                        if(255-MKS[3]==255)
                        {
                            D++;
                        }
                        else ERRO++;
                    }
                    else ERRO++;
                 }
                 else ERRO++;
            }
            else ERRO++;
        }
        else if(IPS[0]>=240&&IPS[0]<=255&&IPS[1]<=255&&IPS[2]<=255&&IPS[3]<=255&&IPS[1]>=0&&IPS[2]>=0&&IPS[3]>=0)
        {
           if(255-MKS[0]==0)
            {
                 if(255-MKS[1]==0||255-MKS[1]==255)
                 {
                    if(255-MKS[2]==0||255-MKS[2]==255)
                    {
                        if(255-MKS[3]==255)
                        {
                            E++;
                        }
                        else ERRO++;
                    }
                    else ERRO++;
                 }
                 else ERRO++;
            }
            else ERRO++;
        }
        else if(IPS[0]==0||IPS[0]==127)
        {
            break;
        }
        else ERRO++;

     end:   memset(IPS,0,sizeof(IPS));
            memset(MKS,0,sizeof(MKS));
            memset(ip_str,0,sizeof(ip_str));
            memset(mks,0,sizeof(mks));
            memset(ips,0,sizeof(ips));
            IPS_I=0;MKS_I=0;
    }
    printf("%d %d %d %d %d %d %d",A,B,C,D,E,ERRO,IP_S);
    return 0;
}
发表于 2023-07-29 11:31:38 回复(1)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


void scan_replace(char *ip, char *pos[]){
    int i = 0;
    int j = 1;
    pos[0] = ip;
    while (ip[i] != '\0' && j < 4){
        if (ip[i++] != '.')
            continue;
        pos[j++] = &ip[i];
        ip[i - 1] = '\0';
    }
}

int check_mask(long long mask){
    int last_digit = mask & ~(mask - 1);
    if (last_digit == 1)
        mask -= 1;
    mask /= last_digit;
    while (mask > 0){
        if (mask % 2 == 0)
            return 0;
        mask >>= 1;
    }
    return 1;
}

// 0~4: A/B/C/D/E, 5: Error, 6~8: A/B/C+Private, -1: 127.*.*.*
int classify(char *ip, char *mask){
    char *ip_groups[4] = {0};
    char *mask_group[4] = {0};
    scan_replace(ip, ip_groups);
    scan_replace(mask, mask_group);
    for (int i = 0; i < 4; i++){
        if (ip_groups[i][0] == '\0' || mask_group[i][0] == '\0')
            return 5;
    }
    long long mask_int = 0;
    for (int i = 0; i < 4; i++){
        mask_int <<= 8;
        int num = atoi(mask_group[i]);
        if (num < 0 || 255 < num)
            return 5;
        mask_int |= num;
    }
    if (mask_int == 0 || mask_int == 0xFFFFFFFF || check_mask(mask_int) == 0)
        return 5;
    long long ip_int = 0;
    for (int i = 0; i < 4; i++){
        int num = atoi(ip_groups[i]);
        if (num < 0 || 255 < num)
            return -5;
        ip_int *= 1000;
        ip_int += num;
    }

    if (0 <= ip_int && ip_int <= 255255255)
        return -1;
    if (127000000000 <= ip_int && ip_int <= 127255255255)
        return -1;

    int ret;
    // A
    if (1000000000 <= ip_int && ip_int <= 126255255255){
        ret = 0;
        if (10000000000 <= ip_int && ip_int <= 10255255255)
            ret += 6;
    // B
    } else if (128000000000 <= ip_int && ip_int <= 191255255255){
        ret = 1;
        if (172016000000 <= ip_int && ip_int <= 172031255255)
            ret += 6;
    // C
    } else if (192000000000 <= ip_int && ip_int <= 223255255255){
        ret = 2;
        if (192168000000 <= ip_int && ip_int <= 192168255255)
            ret += 6;
    // D
    } else if (224000000000 <= ip_int && ip_int <= 239255255255){
        ret = 3;
    // E
    } else if (240000000000 <= ip_int && ip_int <= 255255255255){
        ret = 4;
    } else
        ret = 5;
    return ret;
}

int main(void){
    int i = 0;
    char ch;
    char line[50] = {0};
    char *ip = line, *mask;
    int nums[7] = {0};
    while (scanf("%c", &ch) != EOF){
        if (ch == '\r' || ch == '\n'){
            int which = classify(ip, mask);
            if (which != -1)
                nums[which]++;
            if (which > 6){
                nums[6]++;
                nums[which - 6]++;
            }
            i = 0;
            memset((void*)line, '\0', 50);
            continue;
        }
        line[i++] = ch;
        if (ch == '~'){
            line[i - 1] = '\0';
            mask = &line[i];
        }
    }
    for (int i = 0; i < 7; i++)
        printf("%d ", nums[i]);
    return 0;
}
发表于 2023-04-23 00:23:33 回复(0)
#include <stdio.h>

int main() {
    int ip[4], mk[4];       //IP地址、子网掩码
    int addrType[7] = {};   //地址类型
    int mask, typeId;       //掩码值、类型号
    int endAddr[] =         //类型尾地址
    {126, 191, 223, 239, 255};

    while (scanf("%d.%d.%d.%d~%d.%d.%d.%d", //读取IP地址和子网掩码
                 ip, ip + 1, ip + 2, ip + 3,
                 mk, mk + 1, mk + 2, mk + 3) == 8) {
        if (ip[0] == 0 || ip[0] == 127) //若非指定IP类型
            continue;
        //合并子网掩码为掩码值
        mask = (mk[0] << 24) + (mk[1] << 16) + (mk[2] << 8) + mk[3];
        if (((~mask + 1) & ~mask) || !~mask) {  //若掩码非连续1后0
            addrType[5]++;  //错误IP或掩码+1
            continue;
        }
        if (ip[0] == 10 || (ip[0] == 192 && ip[1] == 168) ||
                (ip[0] == 172 && ip[1] > 15 && ip[1] < 32)) //若为私有地址
            addrType[6]++;  //私有IP类型+1
        for (typeId = 0; ip[0] > endAddr[typeId]; typeId++); //遍历查找匹配类型
        addrType[typeId]++; //对应IP类型+1
    }
    for (typeId = 0; typeId < 7; typeId++)  //遍历地址类型
        printf("%d ", addrType[typeId]);    //打印IP类型数
}

发表于 2023-03-19 15:33:59 回复(1)
#include <stdio.h>

typedef struct ip{
    int A;
    int B;
    int C;
    int D;
    int E;
    int error;
    int privacy;
}IP ;

int main() {
    char str[100] = {};
    IP ipv4 = {0};
    int ip[4] = {0};
    int mask[4] = {0};

    while (scanf("%s", str) != EOF) { // 注意 while 处理多个 case
        int ip_num = 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]);
    
        if(ip[0] == 0 || ip[0] == 127) //不属于任何一类,计数时忽略
            continue; 
        
        //IP地址或子网掩码输入格式错误
        if(ip_num != 8)   
         {
            ipv4.error++;
            continue;
         } 
        
        //判断子网掩码合法性
        if((mask[0] == 0 && mask[1] == 0 && mask[2] == 1 && mask[3] == 0)\
            || (mask[0] == 255 && mask[1] == 255 && mask[2] == 255 && mask[3] == 255))
        {
            ipv4.error++;
            continue;
        }
        int mask32 = 0;
        for(int i=3; i>=0; i--)
        {
            mask32 += mask[i] << 8*(3-i);   //将子网掩码合成32位整数
        }
        mask32 = ~mask32 + 1;   //取反为000…00111…1,然后再加1为00…01000…0,此时为2^n,如果满足就为合法掩码。
        if((mask32 & (mask32-1)) != 0)
        {
            ipv4.error++;
            continue;
        }

        //对正确IP地址分类
        if(ip[0] >= 1 && ip[0] <= 126)
        {
            ipv4.A++;
        }
        else if(ip[0] >= 128 && ip[0] <= 191)
        {
            ipv4.B++;
        }
        else if(ip[0] >= 192 && ip[0] <= 223)
        {
            ipv4.C++;
        }
        else if(ip[0] >= 224 && ip[0] <= 239)
        {
            ipv4.D++;
        }
        else 
        {
            ipv4.E++;
        }

        //私网
        if((ip[0] == 10) || (ip[0] == 172 && ip[1] >= 16 &&ip[1] <= 31) || \
            (ip[0] == 192 && ip[1] == 168))
        {
            ipv4.privacy++;
        }
    }

    printf("%d %d %d %d %d %d %d", ipv4.A,ipv4.B,ipv4.C,ipv4.D,ipv4.E,ipv4.error,ipv4.privacy);
    return 0;
}

发表于 2023-02-08 00:57:55 回复(0)
终于写出来了。写了好久,直到看了榜1大哥的代码才发现原来是我的思路有问题(我还一直以为是题目有问题)。其实这个题目的思路非常简单(我想的太复杂了),先判断IPv4地址和掩码是否合法,再分别判断类别。只不过有几点需要注意,(1)对 0.*.*.* 和 127.*.*.* 的判断必须在对掩码合法性的判断之前进行(这点真的很奇怪,不知道出题人咋想的),建议最好是在对IPv4地址合法性的判断之后进行;(2)A类的10.0.0.0到10.255.255.255,B类的128.0.0.0到191.255.255.255,C类的192.0.0.0到223.255.255.255是私有的。
对IPv4地址和掩码我是用正则表达式来判断的,其中掩码部分的这段代码 ((bin_mask | (bin_mask - 1)) != 0xFFFFFFFF) 参考了榜1大哥的代码,确实挺精妙的,不用白不用。
使用正则表达式确实相对来说要更简单,而且这个正则表达式也不难写(属于是很经典的正则表达式了),但是使用正则表达式的效率非常低,尤其是这么长的正则表达式,而且还匹配了2次,最终花费时间70ms左右,占用内存500多KB,正则虽好用,代价也不小。
下面是我的代码(效率很低,仅供参考)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>

#define IPV4_ADR_AND_MASK_RE "^((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$"

int main() {
    char str[50];
    int class_A_count = 0, class_B_count = 0, class_C_count = 0, class_D_count = 0,
        class_E_count = 0, wrong_ipadr_or_mask_count = 0, private_ip = 0;

    while (fgets(str, 50, stdin) != NULL) {    // 获取字符串
        int len = strlen(str) - 1;
        str[len] = '\0';
        // 将字符串拆分成IPv4地址和掩码
        char* ip_adr = strtok(str, "~");
        char* mask = strtok(NULL, "~");
        // 判断IPv4地址是否合法
        regex_t regex;
        regcomp(&regex, IPV4_ADR_AND_MASK_RE, REG_EXTENDED);
        int reti = regexec(&regex, ip_adr, 0, NULL, 0);
        if (reti) {
            // IPv4地址不合法
            wrong_ipadr_or_mask_count += 1;
            regfree(&regex);
            continue;
        }
        // 判断IPv4地址是否为 0.*.*.* 或 127.*.*.*
        int first_field = atoi(ip_adr);
        if (first_field == 0 || first_field == 127) {
            // IPv4地址是 0.*.*.* 或 127.*.*.*
            regfree(&regex);
            continue;
        }
        // 判断掩码是否合法
        reti = regexec(&regex, mask, 0, NULL, 0);
        if (reti) {
            // 掩码不合法(情况1)
            wrong_ipadr_or_mask_count += 1;
            regfree(&regex);
            continue;
        }
        regfree(&regex);

        unsigned bin_mask = 0;
        char* temp_p = mask;
        unsigned temp = atoi(temp_p);
        for (int i = 0; i < 4; ++i) {
            bin_mask |= temp << ((3 - i) * 8);
            if (i != 3) {
                temp_p = strchr(temp_p, '.') + 1;
                temp = atoi(temp_p);
            }
        }
        if (bin_mask == 0 || bin_mask == 0xFFFFFFFF ||
            ((bin_mask | (bin_mask - 1)) != 0xFFFFFFFF)) {
            // 掩码不合法(情况2)
            wrong_ipadr_or_mask_count += 1;
            continue;
        }
        // 判断IPv4地址是否为A类
        if (1 <= first_field && first_field <= 126) {
            // IPv4地址是A类
            class_A_count += 1;
            // 判断是否是A类的私网IPv4地址
            if (first_field == 10) {
                // 是A类的私网IPv4地址
                private_ip += 1;
            }
            continue;
        }
        // 判断IPv4地址是否为B类
        int second_filed = atoi(strchr(ip_adr, '.') + 1);
        if (128 <= first_field && first_field <= 191) {
            // IPv4地址是B类
            class_B_count += 1;
            // 判断是否是B类的私网IPv4地址
            if (first_field == 172 && (16 <= second_filed && second_filed <= 31)) {
                // 是B类的私网IPv4地址
                private_ip += 1;
            }
            continue;
        }
        // 判断IPv4地址是否为C类
        if (192 <= first_field && first_field <= 223) {
            // IPv4地址是C类
            class_C_count += 1;
            // 判断是否是C类的私网IPv4地址
            if (first_field == 192 && second_filed == 168) {
                // 是C类的私网IPv4地址
                private_ip += 1;
            }
            continue;
        }
        // 判断IPv4地址是否为D类
        if (224 <= first_field && first_field <= 239) {
            // IPv4地址是D类
            class_D_count += 1;
            continue;
        }
        // 判断IPv4地址是否为E类
        if (240 <= first_field && first_field <= 255) {
            // IPv4地址是E类
            class_E_count += 1;
            continue;
        }
    }

    // 输出统计结果
    printf("%d %d %d %d %d %d %d\n", class_A_count, class_B_count, class_C_count,
           class_D_count, class_E_count, wrong_ipadr_or_mask_count, private_ip);

    return 0;
}


发表于 2022-07-02 20:29:25 回复(0)
取巧用了sscanf,省了字符串转数字流程,没有防错
#include <stdio.h>

int main()
{
  char ip_buf[30] ;
  int ip[4], mask[4];
  int A = 0, B = 0, C = 0, D = 0, E = 0, F = 0, S = 0;
  int i, mask_num, mask_flag;
  
  while(scanf("%s", ip_buf) != EOF)
  {
    if(sscanf(ip_buf, "%d.%d.%d.%d~%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3], &mask[0], &mask[1], &mask[2], &mask[3]))
    {
      if(ip[0] == 0 || ip[0] == 127)    // 忽略地址不用判断掩码是否错误
        continue;

      // 判断IP格式是否错误
      for(i = 0; i < 4; i++)
        mask_num = mask_num << 8 | mask[i];

      if(mask_num == 0x00 || mask_num == 0xFFFFFFFF) // 非法掩码
      {
        F++;
        continue;
      }

      /* 从最后一位判断掩码是否有效 */
      for(i = 0, mask_flag = 0; i < 32; i++)
      {
        if((mask_num & 0x01) != mask_flag)  // 出现不一致
        {
          if(mask_flag == 0)  // 0 往前就是1
          {
            mask_flag = 1;
          }
          else  // 1往前不能为0,掩码错误
          {
            F++;
            break;
          }
        }
        mask_num >>= 0x01;
      }

      if(i == 32)
      {
        // 是否为私网地址
        if((ip[0] == 10) || (ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) || (ip[0] == 192 && ip[1] == 168))
          S++;
        
        // 私网地址和公有地址可以共用
        if(ip[0] <= 126)          A++;
        else if(ip[0] <= 191)     B++;
        else if(ip[0] <= 223)     C++;
        else if(ip[0] <= 239)     D++;
        else                      E++;
      }
    }
  }
  
  printf("%d %d %d %d %d %d %d", A, B, C, D, E, F, S);
}


发表于 2022-07-01 14:47:38 回复(0)