首页 > 试题广场 >

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

[编程题]识别有效的IP地址和掩码并进行分类统计
  • 热度指数:329088 时间限制: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

输出

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;
所以最终的结果为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 0 0

说明

类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时请忽略         
#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)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define    N    30
#define    M    1000
int main()
{
    char* str[M], arr[32];
    int i = -1, j, m, n, p, A = 0, B = 0, C = 0, D = 0, E = 0, err = 0, pri = 0, flag, flag1,flag2, cnt, temp[4],num[4];
    do
    {
        i++;
        str[i] = (char*)malloc(sizeof(char) * N);
        gets(str[i]);
    } while (*str[i] != '\0');
    j = i;
    for (i = 0; i < j; i++)
    {
        flag = 0;flag1=0;
        for (cnt = 0; cnt < 4; cnt++)
        {
            num[cnt] = 0;
        }
        if ((*str[i] == '0' && *(str[i] + 1) == '.') || (*str[i] == '1' && *(str[i] + 1) == '2'
            && *(str[i] + 2) == '7' && *(str[i] + 3) == '.'))
        {
            continue;
        }
        else
        {
            cnt = 0; m = 0;
            while (*(str[i] + m) != '~')
            {
                if (*(str[i] + m) == '.'&&*(str[i] + m + 1) != '.')
                {
                    cnt++;
                    m++;
                    continue;
                }
                else if(*(str[i] + m) == '.'&&*(str[i] + m + 1) == '.')
                {
                    num[0]=-1;
                    break;
                }
                num[cnt] *= 10;
                num[cnt] += *(str[i] + m) - '0';
                m++;
            }
            if ((num[0] >= 1 && num[0] <= 126) && (num[1] >= 0 && num[1] <= 255) &&
                (num[2] >= 0 && num[2] <= 255) && (num[3] >= 0 && num[3] <= 255))
            {
                flag = 1;
            }
            else if ((num[0] >= 128 && num[0] <= 191) && (num[1] >= 0 && num[1] <= 255) &&
                (num[2] >= 0 && num[2] <= 255) && (num[3] >= 0 && num[3] <= 255))
            {
                flag = 2;
            }
            else if ((num[0] >= 192 && num[0] <= 223) && (num[1] >= 0 && num[1] <= 255) &&
                (num[2] >= 0 && num[2] <= 255) && (num[3] >= 0 && num[3] <= 255))
            {
                flag = 3;
            }
            else if ((num[0] >= 224 && num[0] <= 239) && (num[1] >= 0 && num[1] <= 255) &&
                (num[2] >= 0 && num[2] <= 255) && (num[3] >= 0 && num[3] <= 255))
            {
                flag = 4;
            }
            else if ((num[0] >= 240 && num[0] <= 255) && (num[1] >= 0 && num[1] <= 255) &&
                (num[2] >= 0 && num[2] <= 255) && (num[3] >= 0 && num[3] <= 255))
            {
                flag = 5;
            }
            if ((num[0] == 10 && (num[1] >= 0 && num[1] <= 255) &&
                (num[2] >= 0 && num[2] <= 255) && (num[3] >= 0 && num[3] <= 255)) ||
                (num[0] == 172 && (num[1] >= 16 && num[1] <= 31) &&
                    (num[2] >= 0 && num[2] <= 255) && (num[3] >= 0 && num[3] <= 255)) ||
                (num[0] == 192 && num[1] == 168 &&
                    (num[2] >= 0 && num[2] <= 255) && (num[3] >= 0 && num[3] <= 255)))
            {
                flag1 = 1;
            }
            if (flag == 0&&flag1==0)
            {
                err++;
            }
            else
            {
                memset(arr, '0', 32);
                flag2 = 0;
                for (cnt = 0; cnt < 4; cnt++)
                {
                    temp[cnt] = 0;
                }
                m++;
                cnt = 0;
                while (*(str[i] + m) != '\0')
                {
                    if (*(str[i] + m) == '.'&&*(str[i] + m + 1) != '.')
                    {
                        cnt++;
                        m++;
                        continue;
                    }
                    else if (*(str[i] + m) == '.'&&*(str[i] + m + 1) == '.')
                    {
                        for(n=0;n<4;n++)
                        {
                            temp[n]=0;
                        }
                        break;
                    }
                    temp[cnt] *= 10;
                    temp[cnt] += *(str[i] + m) - '0';
                    m++;
                }
                if ((temp[0] == 0 && temp[1] == 0 && temp[2] == 0 && temp[3] == 0) ||
                    (temp[0] == 255 && temp[1] == 255 && temp[2] == 255 && temp[3] == 255))
                {
                    err++;
                }
                else
                {
                    for (cnt = 0; cnt < 4; cnt++)
                    {
                        p = 8 * (cnt + 1) - 1;
                        for (n = 0; n < 8; n++)
                        {
                            arr[p--] = temp[cnt] % 2 + '0';
                            temp[cnt] /= 2;
                        }
                    }
                    for (n = 0; n < 32; n++)
                    {
                        if (arr[n] == '0')
                        {
                            flag2 = 1;
                        }
                        else if (arr[n] == '1' && flag2 == 1)
                        {
                            err++;
                            break;
                        }
                    }
                    if (n == 32)
                    {
                        if(flag1==1)
                        {
                            pri++;
                        }
                        switch (flag)
                        {
                        case 1:
                            A++;
                            break;
                        case 2:
                            B++;
                            break;
                        case 3:
                            C++;
                            break;
                        case 4:
                            D++;
                            break;
                        case 5:
                            E++;
                            break;
                        }
                    }
                }
            }
        }
    }
    printf("%d %d %d %d %d %d %d\n", A, B, C, D, E, err, pri);
    return 0;
}

//写了很久终于写出来了,虽然很烂,菜鸡啊

发表于 2022-04-15 09:43:22 回复(0)
第八组案例 实在是过不去了,感觉A类型就70个,我一个一个找的,找出七十个。
发表于 2022-03-03 15:46:53 回复(2)
这道题好奇怪呀,太离谱了
正常的思维,掩码错误了,整个ip地址无需判断,直接按错误ip处理,不对吗?

题目里有这么一句话:
类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时请忽略

我以为不用管,判断完了不属于任何一类就忽略就行了

结果这句话优先级很高,错误的ip也必须先判断不是【0.*.*.*】和【127.*.*.*】,然后才能算进去???

今天程序写完,有一组测试用例怎么也跑不过去
测试用例:
225.240.129.203~255.110.255.255
183.181.49.4~255.0.0.0
172.177.113.45~255.0.0.0
176.134.46.246~255.0.0.0
153.63.21.56~255.255.58.255
23.135.167.228~255.0.0.0
204.58.47.149~255.0.0.0
113.33.181.46~255.255.255.0
73.245.52.119~255.255.154.0
23.214.47.71~255.0.0.0
139.124.188.91~255.255.255.100
142.94.192.197~255.0.0.0
53.173.252.202~255.0.0.0
127.201.56.50~255.255.111.255
118.251.84.111~255.0.0.0
130.27.73.170~255.0.0.0
253.237.54.56~255.86.0.0
64.189.222.111~255.255.255.139
148.77.44.147~255.0.0.0
59.213.5.253~255.255.0.0
3.52.119.131~255.255.0.0
213.208.164.145~255.255.0.0
24.22.21.206~255.255.90.255
89.43.34.31~255.0.0.0
9.64.214.75~255.0.0.0
110.156.20.173~255.153.0.0
71.183.242.53~255.255.0.0
119.152.129.100~255.0.0.0
38.187.119.201~255.0.0.0
73.81.221.180~255.255.255.255
73.198.13.199~255.0.15.0
99.42.142.145~255.255.255.0
196.121.115.160~255.0.0.0
226.30.29.206~255.0.0.0
244.248.31.171~255.255.255.255
59.116.159.246~255.0.0.0
121.124.37.157~255.0.0.226
103.42.94.71~255.255.0.0
125.88.217.249~255.255.74.255
73.44.250.101~255.255.255.0

期待结果是
16 6 3 1 0 13 0

我程序的输出是
16 6 3 1 0 14 0

然后我想知道我程序多算了哪一个,把所有的错误ip打印出来:
225.240.129.203~255.110.255.255
153.63.21.56~255.255.58.255
73.245.52.119~255.255.154.0
139.124.188.91~255.255.255.100
127.201.56.50~255.255.111.255
253.237.54.56~255.86.0.0
64.189.222.111~255.255.255.139
24.22.21.206~255.255.90.255
110.156.20.173~255.153.0.0
73.81.221.180~255.255.255.255
73.198.13.199~255.0.15.0
244.248.31.171~255.255.255.255
121.124.37.157~255.0.0.226
125.88.217.249~255.255.74.255

我对着这14个ip找了几个小时,怎么看全都是错误ip呀
后来在增加错误ip的计数之前,先判断ip第一位不是0和127,就通过了
!!!

代码
#include <stdio.h>

enum Ip_type{
    INVALID = -1,//既不属于任意一类,也不属于不合法ip地址
    A,
    B,
    C,
    D,
    E,
    ERR,//非法ip
};

int test_mask(int *mask);//判断掩码是否合法,合法返回1,不合法返回0
enum Ip_type test_ip(int *ip);//判断ip地址属于哪一种
int test_private(int *ip);//判断ip地址是否是私有ip

int main(){
    int ip[4];//接受ip地址的每部分的数字
    int mask[4];//接受掩码的每部分的数字
    int a, b, c, d, e, err, pri;
    char buf[64];
    enum Ip_type ip_type;
    a = b = c = d = e = err = pri = 0;
    
    //接收数据
    while(scanf("%s", buf) != EOF){
        
        //提取ip地址和掩码到两个数组中
        if(sscanf(buf,"%d.%d.%d.%d~%d.%d.%d.%d", ip, ip+1, ip+2, \
                  ip+3, mask, mask+1, mask+2, mask+3) == 8){
            
            //判断掩码是否合法
            if(test_mask(mask)){
                //掩码合法
                //判断是哪一类ip地址
                ip_type = test_ip(ip);
                switch(ip_type){
                    case A:
                        a++;
                        break;
                    case B:
                        b++;
                        break;
                    case C:
                        c++;
                        break;
                    case D:
                        d++;
                        break;
                    case E:
                        e++;
                        break;
                    case ERR:
                        if(ip[0] != 0 && ip[0] != 127)
                            err++;
                        break;
                    default:
                        break;
                }
                
                //若ip地址合法,判断是否私有
                
                if(ip_type != ERR){
                    
                    if(test_private(ip))
                        pri++;
                }
                
            }else{//掩码不合法
                if(ip[0] != 0 && ip[0] != 127)
                    err++;
                
                //printf("err:%s\n",buf);
            }
            
        //接收ip地址和掩码失败,说明数据不符合规范,非法ip或掩码
        }else{
            if(ip[0] != 0 && ip[0] != 127)
                err++;
        }
    }
    
    printf("%d %d %d %d %d %d %d\n", a, b, c, d, e, err, pri);
    
    return 0;
}

int test_mask(int *mask){
    //全为0或者全为1或者出现更大或更小的数必定非法,否则继续判断
    if( (mask[0] + mask[1] + mask [2] + mask[3]) <= 0 || \
       (mask[0] + mask[1] + mask[2] + mask[3]) >= 255*4 ){
        return 0;
    }else{//这里初步确定不是全0或者全1
        
        //寻找第一个非全1的数字
        int i,j;
        int have_0 = 0;
        for(i = 0; i<4; i++){
            if(mask[i] != 255)
                break;
        }
        
        //判断是否满足二进制下前面连续的1,后面连续的零,或者全零
        //从左到右遍历二进制最后八位,因为用的int保存的,前三个字节的0多出来的不用管
        //出现0则增加have_0的值,当have_0不为0时,若出现1则证明非法
        for(j = 7; j >= 0; j--){
            if( ((mask[i] >> j) & 1) == 0 )
                have_0++;
            else{
                if(have_0)
                    return 0;
            }
        }
        
        //判断余下的掩码,出现不为0的则非法,否则合法
        for(i=i+1; i<4; i++){
            if(mask[i] != 0)
                return 0;
        }
        return 1;
    }
    
}


enum Ip_type test_ip(int *ip){
    if(ip[0] >= 1 && ip[0] <= 126)
        return A;
    if(ip[0] >= 128 && ip[0] <= 191)
        return B;
    if(ip[0] >= 192 && ip[0] <= 223)
        return C;
    if(ip[0] >= 224 && ip[0] <= 239)
        return D;
    if(ip[0] >= 240 && ip[0] <= 255)
        return E;
    
    return INVALID;
}
            
            
int test_private(int *ip){
    if(ip[0] == 10)
        return 1;
    if(ip[0] == 172){
        if(ip[1] >=16 && ip[1] <= 31)
            return 1;
    }
    if(ip[0] == 192 && ip[1] == 168)
        return 1;
    
    return 0;
}


            




发表于 2021-12-20 21:21:29 回复(3)

问题信息

难度:
26条回答 90979浏览

热门推荐

通过挑战的用户

查看代码