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
关键修复与新增说明
IP验证逻辑修复:
- 修正原函数错误的段数判断逻辑,强制要求IP为4段
- 使用
strdup复制输入字符串,避免修改原输入内容 - 增加空输入与数值范围的合法性检查
子网掩码验证修复:
- 修复
ptr - strtok的笔误(改为ptr = strtok) - 新增32位二进制格式掩码的支持与合法性验证
- 实现子网掩码核心规则检查:必须是连续1后跟连续0
- 排除全0的非法子网掩码
- 修复
基础功能补全:
- 新增缺失的
bit_print函数,实现32位二进制输出 - 修正
unpack函数中掩码的笔误(225→255) - 将
pack函数返回值改为unsigned int,避免整数溢出 - 修复主函数中
scanf的指针错误与数组越界问题
- 新增缺失的
CIDR功能实现:
- 新增
get_cidr_prefix函数,计算子网掩码的前缀长度 - 新增
unpack_to_str函数,将32位IP转换为点分字符串 - 主函数中新增网络地址计算与CIDR格式输出逻辑
- 新增
内容的提问来源于stack exchange,提问作者JJChan
相关产品推荐
相关产品推荐

