验证IP地址
- 题目描述
- IPv4 地址规则:
- IPv6 地址规则:
- 示例
- 示例 1
- 示例 2
- 示例 3
- 解题思路
- 1. IPv4 地址验证
- 2. IPv6 地址验证
- 代码实现
- 代码解析
- 1. `isValidIPv4` 函数
- 2. `isValidIPv6` 函数
- 3. `solve` 函数
- 4.token = strtok(NULL, ".");
- 复杂度分析
- 总结
题目描述
编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。
IPv4 地址规则:
- 由 4 个十进制数组成,范围为 0 - 255。
- 用
.
分割。 - 数字不能以 0 开头(除非是 0 本身)。
IPv6 地址规则:
- 由 8 组 16 进制数组成,每组表示 16 比特。
- 用
:
分割。 - 允许前导零,字母可以是大写或小写。
- 不允许空组(如
::
)。 - 不允许多余的 0(如
02001
)。
数据范围:
字符串长度满足 (5 \leq n \leq 50)
进阶要求:
- 空间复杂度 (O(n))
- 时间复杂度 (O(n))
示例
示例 1
输入:
"172.16.254.1"
输出:
"IPv4"
说明:
这是一个有效的 IPv4 地址。
示例 2
输入:
"2001:0db8:85a3:0:0:8A2E:0370:7334"
输出:
"IPv6"
说明:
这是一个有效的 IPv6 地址。
示例 3
输入:
"256.256.256.256"
输出:
"Neither"
说明:
这个地址既不是 IPv4 也不是 IPv6 地址。
解题思路
1. IPv4 地址验证
- 使用
strtok
按.
分割字符串。 - 检查分割后的段数是否为 4。
- 检查每段是否为数字,且范围在 0 - 255 之间。
- 检查是否有前导零(除非是 0 本身)。
2. IPv6 地址验证
- 使用
strtok
按:
分割字符串。 - 检查分割后的段数是否为 8。
- 检查每段是否为有效的 16 进制数(0-9, a-f, A-F)。
- 检查每段长度是否在 1 - 4 之间。
代码实现
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>// 判断是否是有效的 IPv4 地址
int isValidIPv4(char* IP) {int count = 0; // 段数计数器int len = strlen(IP); // 字符串长度char* token = strtok(IP, "."); // 按 '.' 分割字符串if (len == 0 || IP[len - 1] == ':') return 0; // 字符串为空或以冒号结尾,无效while (token) {count++; // 段数加 1if (count > 4 ) return 0; // 段数超过 4 无效int token_len = strlen(token); // 当前段的长度if (token_len == 0 || token_len > 3) return 0; // 段长度为 0 或超过 3,无效int num = 0; // 当前段的数值for (int i = 0; i < token_len; i++) {if (!isdigit(token[i])) return 0; // 字符不是数字,无效num = num * 10 + (token[i] - '0'); // 计算数值}if (num < 0 || num > 255) return 0; // 数值不在 0 - 255 范围内,无效if (token_len > 1 && token[0] == '0') return 0; // 有前导零,无效token = strtok(NULL, "."); // 获取下一个段}return count == 4; // 段数恰好为 4,有效
}// 判断是否是有效的 IPv6 地址
int isValidIPv6(char* IP) {int len = strlen(IP); // 字符串长度if (len == 0 || IP[len - 1] == ':') return 0; // 字符串为空或以冒号结尾,无效int count = 0; // 段数计数器char* token = strtok(IP, ":"); // 按 ':' 分割字符串while (token) {count++; // 段数加 1if (count > 8) return 0; // 段数超过 8,无效int part_len = strlen(token); // 当前段的长度if (part_len == 0 || part_len > 4) return 0; // 段长度为 0 或超过 4,无效for (int i = 0; i < part_len; i++) {if (!isxdigit(token[i])) return 0; // 字符不是 16 进制数字,无效}token = strtok(NULL, ":"); // 获取下一个段}return count == 8; // 段数恰好为 8,有效
}// 主函数,验证 IP 地址类型
char* solve(char* IP) {char* ipCopy = strdup(IP); // 复制 IP 字符串if (isValidIPv4(ipCopy)) {free(ipCopy); // 释放复制的字符串return "IPv4"; // 返回 "IPv4"}free(ipCopy); // 释放复制的字符串ipCopy = strdup(IP); // 再次复制 IP 字符串if (isValidIPv6(ipCopy)) {free(ipCopy); // 释放复制的字符串return "IPv6"; // 返回 "IPv6"}free(ipCopy); // 释放复制的字符串return "Neither"; // 返回 "Neither"
}
代码解析
1. isValidIPv4
函数
- 使用
strtok
按.
分割字符串。 - 检查每段是否为数字,且范围在 0 - 255 之间。
- 检查是否有前导零。
2. isValidIPv6
函数
- 使用
strtok
按:
分割字符串。 - 检查每段是否为有效的 16 进制数。
- 检查每段长度是否在 1 - 4 之间。
3. solve
函数
- 复制 IP 字符串,避免修改原字符串。
- 依次调用
isValidIPv4
和isValidIPv6
进行验证。 - 返回验证结果。
4.token = strtok(NULL, “.”);
- 第一次调用:
第一次调用时,str 是要分割的原始字符串。strtok 会找到第一个分隔符,并将字符串从该位置分割开,返回第一个子字符串的指针。分隔符位置会被替换为 \0(字符串结束符),从而将原字符串分割成两部分。 - 后续调用:
后续调用时,str 参数必须传入 NULL。strtok 会从上次分割的位置继续处理,返回下一个子字符串。这个过程会一直持续,直到没有更多的子字符串为止(此时返回 NULL)。
复杂度分析
- 时间复杂度:(O(n)),其中 (n) 是字符串长度。
- 空间复杂度:(O(n)),用于存储复制的字符串。
总结
方法 | 时间复杂度 | 空间复杂度 | 核心思想 |
---|---|---|---|
分割字符串 | (O(n)) | (O(n)) | 按规则分割并验证每段是否合法 |
这题整体难度看似难度挺大,实际上只要记住一些IP规则即可,还有字符串处理函数。