(C/C++)malloc与strcat搭配使用时所需要注意的细节
起因:
在LINUX环境下
做了一个针对ipv6地址的转换接口,其中一个接口功能是”将所设计的ipv6结构转换成用冒分十六进制表达的字符串“;
在我写好代码进行测试时发现代码产生了如下乱码:
(53�0:0:0:1:0:0:0:0
以下是main里面的调用语句:
int main() {
ipv6_node node;
node.ipv6[0] = 0;;
node.ipv6[1] = 0;;
node.ipv6[2] = 4294967295;;
node.ipv6[3] = 2147483648;;
int a= ipv6_add(&node,31);
printf("ipv6_add是否成功? ans:%d\n",a==0?1:0);
printf("%u,%u,%u,%u\n",node.ipv6[0],node.ipv6[1],node.ipv6[2],node.ipv6[3]);
unsigned char* ss= malloc(20*sizeof(unsigned char));
//ss[0]='\0';
//ss[19]='\0';
ss=ipv6_stringform(&node,ss);
printf("调用ipv6_add之后的地址为: %s\n",ss);
free(ss);
return 0;
}
ipv6_stringform源代码如下(可忽略):
char* ipv6_stringform(const ipv6_node* ipv6_no, char* string) {
char* string_temp=string;
unsigned int temp[8] = { 0,0,0,0,0,0,0,0 };
int t_index = 0;
for (int i = 0; i < 4; ++i) {
for (int j = 0, shift = 16; j < 2; ++j, shift -= 16) {
temp[t_index++] = (ipv6_no->ipv6[i] >> shift) & 0b1111111111111111;
}
}
for (int j = 0; j < 7; ++j) {
char s[3] = { 0,0 };
my_itoa(temp[j], s, 16);
strcat(string_temp, s);
strcat(string_temp, ":");
}
char s[3] = { 0,0 };
my_itoa(temp[7], s, 16);
strcat(string_temp, s);
return string;
}
产生输出:
ipv6_add是否成功? ans:1 0,1,0,0 当前ipv6地址为:h63�0:0:0:1:0:0:0:0
可以看到虽然输出后半部分输出了正确答案,但是前面会产生乱码。
起初认为是因为内存分配之后没有放入’\0’,倒是函数无法判定当前数组是一个字符串。
所以增加了一句ss[19]='\0';
,但随后测试发现还是和之前情况一模一样。
之后观察源码发现,ipv6_stringform函数内部调用的是strcat函数,而拼接规则是将源字符串拼接到目的字符串的结束符’\0’上,直接进行覆盖然后使用源字符串的结束符充当新的字符串结束符;
于是我新增一条语句ss[0]='\0';
新测试结果:
ipv6_add是否成功? ans:1
0,1,0,0
调用ipv6_add之后的地址为: 0:0:0:1:0:0:0:0
现在可以发现ipv6的冒分十六进制表示是没有问题的了。
后面我查看了只进行了malloc内存分配,没有其他初始化操作的字符串数组内部的数据。发现malloc分配之后首先数组数据是众所周知的没有初始化,其次字符串的结束符有可能会在数组随机位置充当无效数据。
于是乎在调用strcat进行拼接时,函数会找到第一个’\0’所在位置,并将其当作目的字符串的结尾。
> 所以在使用malloc进行动态分配,并且要马上使用strcat进行字符串拼接的时候,请在动态数组的第一个值上面填入’\0’。