You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IP子网划分程序故障求助:修复IP/子网掩码验证及开发CIDR功能

IP子网划分程序问题修复与CIDR功能开发求助

我是编程新手,开发了一个由2个C文件和1个头文件组成的IP子网划分程序,目前运行存在以下问题:

  • IP地址验证逻辑错误:输入完整四段式IP(如10.152.34.67)时提示无效,仅输入三段(如10.152.34)时可通过
  • 子网掩码验证失效:无论输入何种子网掩码均提示无效,程序本应支持点分格式与二进制输入,并输出二进制形式
  • CIDR功能缺失或异常:代码可编译运行,但未实现预期的CIDR相关功能

希望获得IP/子网掩码验证逻辑修复及CIDR功能开发的帮助,原代码及修复后的完整代码如下:


修复后主函数(main.c)

#include <stdio.h>
#include <string.h>
#include "ipfunc.h"

/*This program will display the IP address and subnet mask in binary
 format. It will also display the network address in binary and in
 CIDR formats.
*/

int main(void)
{
    int i;
    int ip[4];
    int sub[4];
    char *piece;
    char ip_str[50];
    char ip_str2[50];
    char sub_str[50];
    char sub_str2[50];

    printf("Enter an IP address: ");
    scanf("%s", ip_str);
    strcpy(ip_str2, ip_str);
    if(!ipVal(ip_str2))
    {
        printf("The ip address you entered (%s) is not valid.\n", ip_str);
        return 1;
    }
    piece = strtok(ip_str, ".");
    i = 0;
    while(piece && i < 4)
    {
        ip[i++] = atoi(piece);
        piece = strtok(NULL, ".");
    }
    printf("\nEnter the subnet mask: ");
    scanf("%s", sub_str);
    strcpy(sub_str2, sub_str);
    if(!subVal(sub_str2))
    {
        printf("The subnet mask you entered (%s) is not valid.\n", sub_str);
        return 1;
    }

    piece = strtok(sub_str, ".");
    i = 0;
    while(piece && i < 4)
    {
        sub[i++] = atoi(piece);
        piece = strtok(NULL, ".");
    }

    printf("\nIP Address (binary): ");
    bit_print(pack(ip[0], ip[1], ip[2], ip[3]));
    printf("Subnet Mask (binary): ");
    bit_print(pack(sub[0], sub[1], sub[2], sub[3]));

    printf("IP Address: %s\n", ip_str);
    printf("Subnet Mask: %s\n", sub_str);

    // 计算并输出网络地址与CIDR格式
    unsigned int ip_packed = pack(ip[0], ip[1], ip[2], ip[3]);
    unsigned int sub_packed = pack(sub[0], sub[1], sub[2], sub[3]);
    int cidr_prefix = get_cidr_prefix(sub_packed);
    unsigned int network_packed = ip_packed & sub_packed;
    char network_str[50];
    unpack_to_str(network_packed, network_str);
    printf("Network Address: %s/%d\n", network_str, cidr_prefix);

    printf("\nThank you for using ip158.\n");

    return 0;
}

修复后ipfunc.c

#include "ipfunc.h"
#include <string.h>
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <stdlib.h>

// 验证字符串是否全为数字
int val_digit(char *ptr)
{
    while(*ptr)
    {
        if(!isdigit(*ptr))
        {
            return 0;
        }
        ptr++;
    }
    return 1;
}

// 验证单个子网掩码段的合法数值
int valid_sub_octet(int num)
{
    int sub[] = {0, 128, 192, 224, 240, 248, 252, 254, 255};
    int i;
    for (i = 0; i < 9; i++)
    {
        if (num == sub[i])
        {
            return 1;
        }
    }
    return 0;
}

// 将四段整数打包为32位无符号IP地址
unsigned int pack(int a, int b, int c, int d)
{
    unsigned int p = (unsigned int)a;
    p = (p << CHAR_BIT) | (unsigned int)b;
    p = (p << CHAR_BIT) | (unsigned int)c;
    p = (p << CHAR_BIT) | (unsigned int)d;
    return p;
}

// 从32位IP中提取第k段(0-3)
unsigned char unpack(unsigned int p, int k)
{
    int n = k * CHAR_BIT;
    unsigned int mask = 0xFF;
    mask <<= n;
    return (unsigned char)((p & mask) >> n);
}

// 将32位IP转换为点分字符串
void unpack_to_str(unsigned int p, char *str)
{
    unsigned char octets[4];
    octets[0] = unpack(p, 0);
    octets[1] = unpack(p, 1);
    octets[2] = unpack(p, 2);
    octets[3] = unpack(p, 3);
    sprintf(str, "%u.%u.%u.%u", octets[0], octets[1], octets[2], octets[3]);
}

// 二进制打印32位IP地址
void bit_print(unsigned int p)
{
    for(int i = 31; i >= 0; i--)
    {
        putchar((p >> i) & 1 ? '1' : '0');
        if(i % 8 == 0)
            putchar(' ');
    }
    putchar('\n');
}

// 验证IP地址合法性
int ipVal(char *ip_str)
{
    if (ip_str == NULL || strlen(ip_str) == 0)
        return 0;

    char *buff = strdup(ip_str);
    if(buff == NULL) return 0;

    char *ptr = strtok(buff, ".");
    int segment_count = 0;

    while (ptr)
    {
        if (!val_digit(ptr))
        {
            free(buff);
            return 0;
        }
        int num = atoi(ptr);
        if (num < 0 || num > 255)
        {
            free(buff);
            return 0;
        }
        segment_count++;
        ptr = strtok(NULL, ".");
    }
    free(buff);
    return segment_count == 4 ? 1 : 0;
}

// 验证子网掩码合法性(支持点分格式和32位二进制格式)
int subVal(char *sub_str)
{
    if (sub_str == NULL || strlen(sub_str) == 0)
        return 0;

    // 检查是否是32位二进制字符串
    int len = strlen(sub_str);
    if(len == 32)
    {
        for(int i=0; i<32; i++)
        {
            if(sub_str[i] != '0' && sub_str[i] != '1')
                return 0;
        }
        // 二进制掩码必须是连续1后跟连续0
        int found_zero = 0;
        for(int i=0; i<32; i++)
        {
            if(sub_str[i] == '0')
                found_zero = 1;
            else if(found_zero)
                return 0;
        }
        return 1;
    }

    // 处理点分格式
    char *buff = strdup(sub_str);
    if(buff == NULL) return 0;

    char *ptr = strtok(buff, ".");
    int segment_count = 0;
    int found_non_255 = 0;

    while (ptr)
    {
        if (!val_digit(ptr))
        {
            free(buff);
            return 0;
        }
        int num = atoi(ptr);
        if (!valid_sub_octet(num))
        {
            free(buff);
            return 0;
        }
        // 子网掩码规则:前段为255,遇到非255段后后续必须为0
        if(found_non_255)
        {
            if(num != 0)
            {
                free(buff);
                return 0;
            }
        }
        else
        {
            if(num != 255)
                found_non_255 = 1;
        }
        segment_count++;
        ptr = strtok(NULL, ".");
    }
    free(buff);
    if(segment_count != 4)
        return 0;
    // 排除全0的非法掩码
    unsigned int packed = pack(atoi(strtok(strdup(sub_str), ".")),
                               atoi(strtok(NULL, ".")),
                               atoi(strtok(NULL, ".")),
                               atoi(strtok(NULL, ".")));
    if(packed == 0)
        return 0;
    return 1;
}

// 从32位子网掩码获取CIDR前缀长度
int get_cidr_prefix(unsigned int sub_packed)
{
    int count = 0;
    while(sub_packed)
    {
        count += sub_packed & 1;
        sub_packed >>= 1;
    }
    return count;
}

修复后ipfunc.h

#ifndef IPFUNC_H
#define IPFUNC_H

#include <stdio.h>
#include <stdint.h>

unsigned int pack(int a, int b, int c, int d);
unsigned char unpack(unsigned int p, int k);
void unpack_to_str(unsigned int p, char *str);
void bit_print(unsigned int p);
int ipVal(char *ip_str);
int subVal(char *sub_str);
int get_cidr_prefix(unsigned int sub_packed);

#endif // IPFUNC_H

关键修复与新增说明

  1. IP验证逻辑修复:

    • 修正原函数错误的段数判断逻辑,强制要求IP为4段
    • 使用strdup复制输入字符串,避免修改原输入内容
    • 增加空输入与数值范围的合法性检查
  2. 子网掩码验证修复:

    • 修复ptr - strtok的笔误(改为ptr = strtok)
    • 新增32位二进制格式掩码的支持与合法性验证
    • 实现子网掩码核心规则检查:必须是连续1后跟连续0
    • 排除全0的非法子网掩码
  3. 基础功能补全:

    • 新增缺失的bit_print函数,实现32位二进制输出
    • 修正unpack函数中掩码的笔误(225→255)
    • 将pack函数返回值改为unsigned int,避免整数溢出
    • 修复主函数中scanf的指针错误与数组越界问题
  4. CIDR功能实现:

    • 新增get_cidr_prefix函数,计算子网掩码的前缀长度
    • 新增unpack_to_str函数,将32位IP转换为点分字符串
    • 主函数中新增网络地址计算与CIDR格式输出逻辑

内容的提问来源于stack exchange,提问作者JJChan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 14:25:16