起源

事情是这样的,我在编写一段Unicode解析的代码时,需要先判断输入的Unicode后面从’\u’后是否为4位16进制数,如果是的话,就将这几位复制到一段字符串中并进行解析,如果不是的话则抛出异常。

这段代码如下:

1
2
3
4
5
6
7
8
9
char *high = NULL, *low = NULL;
p = charcpy(p, high);
if(!p)return NULL;
if(*p == '\\'){
p++;
p = charcpy(p, low);
if(!p)return NULL;
}

其中,charcpy函数的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static const char* charcpy(const char* p, char* target){
target = (char *)malloc(5 * sizeof(char));
int len;
for(len = 0; len < 4; len++){
int flag = ((*p)>='0' && (*p)<='9') || ((*p)>='A' && (*p)<='F') || ((*p) >= 'a' && (*p) <= 'f');
if(!flag)return NULL;
target[len] = *p;
p++;
}
printf("\n");
target[len] = '\0';
for(len = 0; len < 4; len++){
printf("%c",target[len]);
}
printf("\n");
return p;
}

首先为target分配内存,然后循环判断p的值是否为16进制数,是的话则赋值给target,否则就直接返回空。

想法很美好,然而现实很崩溃。当我编译运行时则爆出segmentation fault,,这时我debug的时候,发现high仍为空,也就是说charcpy这个函数里的操作并没有改变high。

传值与传指针

C函数传递参数有两种参数,值传递与指针传递。而事实上指针传递也可以看成是值传递,只不过传的类型是指针。当我们将high指针传入函数时,此时的target指向high,但当我们为target指针分配内存的时候,此时target指针将不再指向high,而是脱离出来重新分配内存。解决方法则是使用二重指针传递,当我们使用二重指针的时候,此时target与&high等价,因此我们对*target进行分配内存时,则可以对high进行修改了。

修改后代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static const char* charcpy(const char* p, char** target){
*target = (char *)malloc(5 * sizeof(char));
int len;
for(len = 0; len < 4; len++){
int flag = ((*p)>='0' && (*p)<='9') || ((*p)>='A' && (*p)<='F') || ((*p) >= 'a' && (*p) <= 'f');
if(!flag)return NULL;
(*target)[len] = *p;
p++;
}
(*target)[len] = '\0';
for(len = 0; len < 4; len++){
printf("%c",(*target)[len]);
}
printf("\n");
return p;
}