C++实现IPV6地址压缩
题目要求:给定一组IPV6地址(unsigned 0x),以文字形式输出压缩后的地址
一般要求
https://zhidao.baidu.com/question/542996523.html
注:若有超过两个地方有连续0,选择较长的那个进行压缩
输入:
1234:0abc:0000:0078:ff00:0000:0030:0005
2001:0db8:0000:0000:0001:0000:0000:0000
输出:
1234: abc:0:78:ff00:0:30:5
2001:db8:0:0:1::
具体函数:
unsigned char v1[] = {0x12, 0x34, 0x0a, 0xbc, 0x00, 0x00, 0x00, 0x78, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x05};
unsigned char v2[] = {0x20, 0x01, 0x0d, 0xb8, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x08};
unsigned char v3[] = {0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char v4[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x70, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04};
unsigned char v5[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
unsigned char v6[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
对于每一个数组调用一次转换函数并将每次的结果存在一个字符数组中并输出。
可分为两步:
① 第一次扫描数组,找出数组中最多 0 的其实地方并记录长度
② 第二次扫描数组,一边扫描一边输出
一、
IPV6是8组十六进制的数字那么可以用
bool isZero = false;
for(int i=0;i<8;i++)
{
if( v[2*i] == 0 && v[2*i+1] == 0)
isZero = true;
}
来遍历这个数组(v是16位unsigned数组)
同时还要记录启示下标和最大
bool isZero = false;
int pos = 0;// referencing the start of longest 0s
int length = 0;//the longest 0s
int count = 0;//current count of 0s
for(int i=0;i<8;i++)
{
if( v[2*i] == 0 && v[2*i+1] == 0)
{
isZero = true;
if(isZero)
count++;
if(count > length){//record the new and larger one
pos = i;
length = count;
}
}
else
{
isZero = false;
count = 0;//clear
}
}
通过这一段代码,length就记录了最长0的位置,pos记录了起始位置(八组数字中的第几组开始是最长0)
二、转成文本并压缩
/*
toHex是一个接收一个unsigned,返回一个char的函数
eg. unsigned a = 0xb;
char b = toHex(a);//b = 'b'
*/
char *a = new char[40]; // IPv6 address in text format is up to 40 chars, including '\0'
假设到了要压缩的地方
i = pos = 0, length = 3(假设)
在这种情况下,就是
a[pos] = a[pos+1] = ':';
并且原数组中将会是 0000 0000 (两个为一位,共4个数)1234 etc.
若工作指针是i,要跳过中间的0
假设循环如下
int h = 0;//h: 0 ~ 7指向第几组
int k = 0;//填充到第k个字符
while(h < 7)
{
if( h == pos)
{
a[k++] = a[k++] = ':';//2 consecutive : and update k
h += length;//length groups of 0s
}
else
{
//convert to text form
for(int k = 0; k < 2; k++)
{
//v[2*h] = 0x12, v[2*h+1] = 0x34, for example
//convert it to single digit to use toHex
unsigned d1 = v[2*h] / 16;//d1 = 1
unsigned d2 = v[2*h + 1] % 16;//d2 = 2
//deleting the preceeding 0s
}
}
if( h < 7 && h + 1 != pos)
a[k++] = ':';
h++;
}
a[k] = '\0';
h是指向第几组十六进制数,每个h相当于包含了两个v[i], 即两位的hex,要将一组hex转成四个字符需要:
共有两个v[i]即v[2h] 和 v[2h+1],每个v[i]可能会转成两个char
考虑这几种情况:
v[ 2h] = 0x00, v [2h+1] = 0x01 : 不输出v[2h], 且跳过v[2h+1]前的0,即跳过v[2h+1] 转成的两个字符中的第一个
v [2h] = 0x00, v [2h+1] = 0x00 : 不输出v[2h], 跳过v[2h+1] 转成的两个字符中的第一个,但是第二个0保留输出
v [2h] = 0x01, v [2h+1] = 0x00 : 跳过v[2h]的第一个字符(0), v[2h+1] (的0)保留输出
v [2h] = 0x10, v [2h+1] = 0x00 : 原样输出v [2h], v [2*h+1] ,所有0都要保留
for(int k = 0; k < 2; k++)
{
//v[2*h] = 0x12, v[2*h+1] = 0x34, for example
//convert it to single digit to use toHex
unsigned d1 = v[2*h] / 16;//d1 = 1
unsigned d2 = v[2*h + 1] % 16;//d2 = 2
//deleting the preceeding 0s
for(int j = 0; j < 2 ;j++)
{
//converting v[2*h+j] into 2 char
unsigned d1 = v[2*h + j] / 16;//d1 = 1
unsigned d2 = v[2*h + j] % 16;//d2 = 2
//判断是否需要输出d1
if( d1 > 0 || (j == 1 && v[2*h] >0)
//1. d1 > 0 如12中的1-->输出
//2. d1 = 0 && 是第二位 && 上一个两位数(v[2*h] > 0)
//例如:1000,v[2*h] = 0x10, v[2*h+1] = 0x00, 需要输出1000(后两个0照样输出,因为v[2*h] = 10,> 0)
a[k++] = toHex(d1);
//判断是否需要输出d2
if(d2 > 0 || d1 > 0 || j == 1)
a[k++] = toHex(d2);
//d2 > 0 --->输出
//d2 = 0: d1 > 0 : 10中的0
// j == 1, 即,第二位中的第二个字符,不管是非0数中的0,还是全0(最后要输出一个的0),都应输出
}
}
通过以上过程,将unsigned v[16] 储存的16组而进驻数 转化成了一个存放在a中的字符串