以下是我以前从未见过并且从未见过的代码。 只有一行代码更改rvalue指针并将其设置为NULL
if ((*v)->r != NULL)
printf("WTF r != NULL r %p p %p p->l %p (*v) %p \n",(*v)->r,(*v)->p,(*v)->p->l,(*v));
(*v)->p->l = (*v)->r;
if ((*v)->r == NULL)
printf("WTF r == NULL r %p p %p p->l %p (*v) %p \n",(*v)->r,(*v)->p,(*v)->p->l,(*v));
这两条消息都已打印出来。 r和l设置为NULL。 这很奇怪。
下面的是我尝试调试的所有代码。 您可以编译并运行它。 非常感谢你!!! 这是一个Avl树
AVL_tree.h
#if !defined AVL_TREE_H
#define AVL_TREE_H
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
struct vertex{
int data;
long height;
struct vertex *l,*r,*p;
};
void insert(struct vertex** root, int data);
void* find(struct vertex* root, int data);
void clear_tree(struct vertex** root);
void print_tree(struct vertex* root);
#endif
AVL_tree.c
#include"./AVL_tree.h"
static long
max(long a, long b)
{
return (((a) > (b)) ? a : b);
}
static long
balance_factor(struct vertex *v)
{
if (v->l == NULL && v->r == NULL)
return 0;
else if (v->l == NULL)
return (-1) - v->r->height;
else if (v->r == NULL)
return v->l->height - (-1);
return (v->l->height - v->r->height);
}
static void
update_height(struct vertex *v)
{
if (v->l == NULL
&& v->r == NULL) {
v->height = 0;
return;
} else if (v->l == NULL) {
v->height = v->r->height + 1;
return;
} else if (v->r == NULL) {
v->height = v->l->height + 1;
return;
}
v->height = max(v->l->height, v->r->height) + 1;
}
static void
right_rotate(struct vertex **v)
{
if ((*v)->p != NULL) {
if ((*v)->p->l == (*v))
(*v)->p->l = (*v)->l;
else
(*v)->p->r = (*v)->l;
}
struct vertex *tmp = (*v)->l->r;
(*v)->l->r = (*v);
(*v)->l->p = (*v)->p;
(*v)->p = (*v)->l;
(*v)->l = tmp;
if (tmp != NULL)
tmp->p = (*v);
update_height(*v);
(*v) = (*v)->p;
update_height(*v);
}
static void
left_rotate(struct vertex **v)
{
if ((*v)->r == NULL)
printf("1 r == NULL\n");
if ((*v)->p != NULL) {
printf(" p is not NULL\n");
if ((*v)->p->r == (*v))
(*v)->p->r = (*v)->r;
else if ((*v)->p->l == (*v)) {
printf("p's l == v\n");
if ((*v)->r != NULL)
printf("WTF r != NULL r %p p %p p->l %p (*v) %p \n",(*v)->r,(*v)->p,(*v)->p->l,(*v));
(*v)->p->l = (*v)->r;
if ((*v)->r == NULL)
printf("WTF r == NULL r %p p %p p->l %p (*v) %p \n",(*v)->r,(*v)->p,(*v)->p->l,(*v));
} else {
printf("error case \n");
}
}
printf("get there before\n");
if ((*v)->r == NULL)
printf("r == NULL\n");
struct vertex *tmp = (*v)->r->l;
printf("get there after\n");
(*v)->r->l = (*v);
printf("get there \n");
(*v)->r->p = (*v)->p;
(*v)->p = (*v)->r;
(*v)->r = tmp;
printf("get there \n");
if (tmp != NULL)
tmp->p = (*v);
printf("get there \n");
update_height(*v);
(*v) = (*v)->p;
update_height(*v);
}
static void
insert_fixup(struct vertex *new_vertex)
{
while ((new_vertex->p != NULL)
&& ((new_vertex->height + 1) > new_vertex->p->height)) {
update_height(new_vertex->p);
new_vertex = new_vertex->p;
if (balance_factor(new_vertex) == 2) {
if (balance_factor(new_vertex->l) == -1) {
printf("double left right rotating \n");
left_rotate(&new_vertex->l);
}
right_rotate(&new_vertex);
return;
} else if (balance_factor(new_vertex) == -2) {
if (balance_factor(new_vertex->r) == 1) {
printf("double right left rotating \n");
right_rotate(&new_vertex->r);
printf("double right rotating finish\n");
}
left_rotate(&new_vertex);
return;
}
}
}
void
insert(struct vertex **tree, int data)
{
struct vertex *new_vertex = malloc(sizeof(struct vertex));
new_vertex->data = data;
new_vertex->height = 0;
new_vertex->l = NULL;
new_vertex->r = NULL;
new_vertex->p = NULL;
if (tree == NULL)
return;
else if (*tree == NULL) {
*tree = new_vertex;
return;
}
struct vertex *root = *tree;
while (1) {
if (root->data < data) {
if (root->r != NULL)
root = root->r;
else {
root->r = new_vertex;
new_vertex->p = root;
break;
}
} else {
if (root->l != NULL)
root = root->l;
else {
root->l = new_vertex;
new_vertex->p = root;
break;
}
}
}
insert_fixup(new_vertex);
while ((*tree)->p != NULL) {
(*tree) = (*tree)->p;
}
}
void *
find(struct vertex *v, int data)
{
while (v != NULL && v->data != data)
if (v->data < data)
v = v->r;
else
v = v->l;
return v;
}
static void
free_tree(struct vertex *root)
{
if (root->l != NULL)
free_tree(root->l);
if (root->r != NULL)
free_tree(root->r);
free(root);
return;
}
void
clear_tree(struct vertex **root)
{
free_tree(*root);
*root = NULL;
}
test.c的
#include"./AVL_tree.h"
#include<stdio.h>
#include<time.h>
int main(){
time_t t;
srand(time(&t));
struct vertex* root = NULL;
int i,j,limit = 1000000,incretment = 500000;
printf("starting insert %d elements with increment %d in next round\n",limit,incretment);
for (j = 0; j <= 100; j++){
clock_t start,end;
start = clock();
for (i = 0; i < limit;i++){
int random = rand() % 10;
printf("inserting %d \n",random);
insert(&root,random);
}
end = clock();
double total = (double)(end - start)/CLOCKS_PER_SEC;
printf("%f\n",total);
clear_tree(&root);
}
}
答案 0 :(得分:1)
当我接受你的代码时,将void
添加到int main()
以使其超过我的编译选项,并重新格式化代码以便它或多或少地正常缩进,然后我得不到编译警告。为此,你有我的赞美; SO上显示的程序非常少,只需要很少的编辑就可以通过我的默认编译选项:
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Werror -c test.c
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Werror -c AVL_tree.c
gcc -g -o avl test.o AVL_tree.o
当我在valgrind
下运行时,我会被告知:
starting insert 1000000 elements with increment 500000 in next round
inserting 0
inserting 6
inserting 1
double right left rotating
==47254== Invalid read of size 8
==47254== at 0x100000FB5: right_rotate (AVL_tree.c:54)
==47254== by 0x10000159E: insert (AVL_tree.c:138)
==47254== by 0x100001AB6: main (test.c:20)
==47254== Address 0x18 is not stack'd, malloc'd or (recently) free'd
==47254==
==47254==
==47254== Process terminating with default action of signal 11 (SIGSEGV)
==47254== Access not within mapped region at address 0x18
==47254== at 0x100000FB5: right_rotate (AVL_tree.c:54)
==47254== by 0x10000159E: insert (AVL_tree.c:138)
==47254== by 0x100001AB6: main (test.c:20)
在格式化的代码中,第54行是struct vertex *tmp
行:
(*v)->p->l = (*v)->l;
else
(*v)->p->r = (*v)->l;
}
struct vertex *tmp = (*v)->l->r;
(*v)->l->r = (*v);
(*v)->l->p = (*v)->p;
(*v)->p = (*v)->l;
(*v)->l = tmp;
if (tmp != NULL)
tmp->p = (*v);
地址0x18强烈暗示您已取消引用空指针。它是一个小于NULL的偏移量,在64位机器上,我认为地址偏移量0x18对应于结构中的r
。无论如何,您的代码似乎没有以某种方式考虑空指针。
另一次出场:
starting insert 1000000 elements with increment 500000 in next round
inserting 6
inserting 2
inserting 3
double left right rotating
p is not NULL
p's l == v
WTF r != NULL r 0x100aa85d0 p 0x100aa84f0 p->l 0x100aa8560 (*v) 0x100aa8560
WTF r == NULL r 0x0 p 0x100aa8560 p->l 0x0 (*v) 0x100aa85d0
get there before
r == NULL
==47387== Invalid read of size 8
==47387== at 0x100001134: left_rotate (AVL_tree.c:99)
==47387== by 0x10000157F: insert (AVL_tree.c:128)
==47387== by 0x100001AB6: main (test.c:20)
==47387== Address 0x10 is not stack'd, malloc'd or (recently) free'd
==47387==
==47387==
==47387== Process terminating with default action of signal 11 (SIGSEGV)
==47387== Access not within mapped region at address 0x10
==47387== at 0x100001134: left_rotate (AVL_tree.c:99)
==47387== by 0x10000157F: insert (AVL_tree.c:128)
==47387== by 0x100001AB6: main (test.c:20)
同样,这表明空指针取消引用。
我建议添加一堆断言,检查所有你认为不能为零的指针实际上都不为空 - 其中一些指针实际上是空的。
我还建议使用其他main()
程序。保持当前的一个,以便以后,当事情大部分工作,你想要压力测试代码。现在,您需要一个简单的确定性程序。您应该尝试插入序列0, 6, 1
和6, 2, 3
,看看是否发生了崩溃。如果是这样,您可以调试它们,并在代码中查找并行问题。 (与第二次崩溃相同的另一个较长的序列是3, 4, 1, 1, 4, 3, 1, 7, 5, 1, 7
;另一个是4, 5, 4, 3, 2, 2, 4, 2, 5, 0, 2
。)
我注意到您的标头本身不应包含任何其他标头。标头应该只包括那些使代码可以自行编译所必需的其他标头。您的结构不使用<stdio.h>
,<stdlib.h>
或<assert.h>
中定义的任何功能,因此这些标题都不应包括在内。您在发布的代码中实际上没有任何断言,但实现代码中需要另外两个头,并且测试代码中需要<stdio.h>
;但它们应该直接包括在内。
请注意,在使用断言进行调试时,请进行独立断言。如果你写:
assert((*v) != NULL && (*v)->r != NULL);
并且断言触发,你无法分辨这两个条件中的哪一个失败了。使用独立的断言:
assert((*v) != NULL);
assert((*v)->r != NULL);
但是就像那样排序 - 而不是相反。这告诉你哪两个条件是错误的。
我在AVL_tree.c
中为您的代码添加了一些工具,使用<inttypes.h>
中提供的格式根据我的偏见设置指针格式,而不是让%p
格式为我做(它将空指针打印为0x0
而不是使用与其他指针类似的宽度 - 而不是我想要的可读输出;使用%.9
是一个适用于这个64位机器的黑客[Mac OS X 10.11 .3,GCC 5.3.0];堆栈地址大约是12个十六进制数字宽,因此它可能是片状格式化)。我创建了一个最小的确定性测试程序avl2.c
。
AVL_tree.c
#include "AVL_tree.h"
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
static void dump_vertex(const char *tag, struct vertex *v)
{
if (v == NULL)
printf("%s: data ; height ; v = 0x%.9" PRIXPTR "\n", tag, (uintptr_t)v);
else
printf("%s: data %d; height %ld; v = 0x%.9" PRIXPTR ", l = 0x%.9"
PRIXPTR ", r = 0x%.9" PRIXPTR ", p = 0x%.9" PRIXPTR "\n",
tag, v->data, v->height, (uintptr_t)v, (uintptr_t)v->l,
(uintptr_t)v->r, (uintptr_t)v->p);
}
static void dump_tree_inorder_notag(const struct vertex *v)
{
if (v != NULL)
{
dump_tree_inorder_notag(v->l);
printf("data %d; height %ld; v = 0x%.9" PRIXPTR ", l = 0x%.9" PRIXPTR
", r = 0x%.9" PRIXPTR ", p = 0x%.9" PRIXPTR "\n",
v->data, v->height, (uintptr_t)v, (uintptr_t)v->l,
(uintptr_t)v->r, (uintptr_t)v->p);
dump_tree_inorder_notag(v->r);
}
}
static void dump_tree_inorder(const char *tag, struct vertex *v)
{
printf("-->> %s: (root 0x%.9" PRIXPTR ")\n", tag, (uintptr_t)v);
dump_tree_inorder_notag(v);
printf("<<-- %s:\n", tag);
}
static inline long
max(long a, long b)
{
return(((a) > (b)) ? a : b);
}
static long
balance_factor(struct vertex *v)
{
assert(v != NULL);
if (v->l == NULL && v->r == NULL)
return 0;
else if (v->l == NULL)
return (-1) - v->r->height;
else if (v->r == NULL)
return v->l->height - (-1);
return(v->l->height - v->r->height);
}
static void
update_height(struct vertex *v)
{
assert(v != NULL);
if (v->l == NULL && v->r == NULL)
{
v->height = 0;
return;
}
else if (v->l == NULL)
{
v->height = v->r->height + 1;
return;
}
else if (v->r == NULL)
{
v->height = v->l->height + 1;
return;
}
v->height = max(v->l->height, v->r->height) + 1;
}
static void
right_rotate(struct vertex **v)
{
if ((*v)->p != NULL)
{
if ((*v)->p->l == (*v))
(*v)->p->l = (*v)->l;
else
(*v)->p->r = (*v)->l;
}
struct vertex *tmp = (*v)->l->r;
(*v)->l->r = (*v);
(*v)->l->p = (*v)->p;
(*v)->p = (*v)->l;
(*v)->l = tmp;
if (tmp != NULL)
tmp->p = (*v);
update_height(*v);
(*v) = (*v)->p;
update_height(*v);
}
static void
left_rotate(struct vertex **v)
{
assert(v != NULL);
assert(*v != NULL);
dump_vertex("-->> left_rotate", *v);
if ((*v)->r == NULL)
printf("1 r == NULL\n");
if ((*v)->p != NULL)
{
printf("p is not NULL\n");
if ((*v)->p->r == (*v))
{
(*v)->p->r = (*v)->r;
}
else if ((*v)->p->l == (*v))
{
printf("p's l == v\n");
dump_vertex("LR1 - current node", *v);
dump_vertex("LR1 - parent node", (*v)->p);
dump_vertex("LR1 - parent left", (*v)->p->l);
dump_vertex("LR1 - current right", (*v)->r);
dump_tree_inorder("LR1 - tree from parent", (*v)->p);
//if ((*v)->r != NULL)
//printf("WTF r != NULL r %p p %p p->l %p (*v) %p\n", (*v)->r, (*v)->p, (*v)->p->l, (*v));
printf("Assign (*v)->r (0x%.9" PRIXPTR ") to (*v)->p->l (0x%.9" PRIXPTR ")\n",
(uintptr_t)(*v)->r, (uintptr_t)(*v)->p->l);
(*v)->p->l = (*v)->r;
dump_vertex("LR2 - current node", *v);
dump_vertex("LR2 - parent node", (*v)->p);
dump_vertex("LR2 - parent left", (*v)->p->l);
dump_vertex("LR2 - current right", (*v)->r);
// At this point, we don't have a tree
//dump_tree_inorder("LR2 - tree from parent", (*v)->p);
//if ((*v)->r == NULL)
//printf("WTF r == NULL r %p p %p p->l %p (*v) %p\n", (*v)->r, (*v)->p, (*v)->p->l, (*v));
}
else
{
printf("error case\n");
}
}
else
dump_vertex("(*v)->p == NULL", (*v)->p);
printf("get there before\n");
if ((*v)->r == NULL)
printf("r == NULL\n");
assert((*v)->r != NULL);
struct vertex *tmp = (*v)->r->l;
printf("get there after\n");
(*v)->r->l = (*v);
printf("get there\n");
(*v)->r->p = (*v)->p;
(*v)->p = (*v)->r;
(*v)->r = tmp;
printf("get there\n");
if (tmp != NULL)
tmp->p = (*v);
printf("get there\n");
update_height(*v);
(*v) = (*v)->p;
update_height(*v);
dump_vertex("<<-- left_rotate", *v);
}
static void
insert_fixup(struct vertex *new_vertex)
{
dump_tree_inorder("insert fixup 0", new_vertex);
while ((new_vertex->p != NULL)
&& ((new_vertex->height + 1) > new_vertex->p->height))
{
update_height(new_vertex->p);
new_vertex = new_vertex->p;
if (balance_factor(new_vertex) == 2)
{
if (balance_factor(new_vertex->l) == -1)
{
printf("double left right rotating\n");
left_rotate(&new_vertex->l);
printf("double left right rotating finish\n");
}
right_rotate(&new_vertex);
dump_tree_inorder("insert fixup 1", new_vertex);
return;
}
else if (balance_factor(new_vertex) == -2)
{
if (balance_factor(new_vertex->r) == 1)
{
printf("double right left rotating\n");
right_rotate(&new_vertex->r);
printf("double right rotating finish\n");
}
left_rotate(&new_vertex);
dump_tree_inorder("insert fixup 2", new_vertex);
return;
}
}
dump_tree_inorder("insert fixup 3", new_vertex);
}
void
insert(struct vertex **tree, int data)
{
assert(tree != NULL);
struct vertex *new_vertex = malloc(sizeof(struct vertex));
assert(new_vertex != NULL);
new_vertex->data = data;
new_vertex->height = 0;
new_vertex->l = NULL;
new_vertex->r = NULL;
new_vertex->p = NULL;
if (tree == NULL)
return;
else if (*tree == NULL)
{
*tree = new_vertex;
dump_tree_inorder("insert-1", *tree);
return;
}
struct vertex *root = *tree;
while (1)
{
if (root->data < data)
{
if (root->r != NULL)
root = root->r;
else
{
root->r = new_vertex;
new_vertex->p = root;
break;
}
}
else
{
if (root->l != NULL)
root = root->l;
else
{
root->l = new_vertex;
new_vertex->p = root;
break;
}
}
}
insert_fixup(new_vertex);
while ((*tree)->p != NULL)
{
(*tree) = (*tree)->p;
}
dump_tree_inorder("insert-2", *tree);
}
void *
find(struct vertex *v, int data)
{
while (v != NULL && v->data != data)
if (v->data < data)
v = v->r;
else
v = v->l;
return v;
}
static void
free_tree(struct vertex *root)
{
if (root->l != NULL)
free_tree(root->l);
if (root->r != NULL)
free_tree(root->r);
free(root);
}
void
clear_tree(struct vertex **root)
{
free_tree(*root);
*root = NULL;
}
avl2.c
#include "AVL_tree.h"
#include <stdio.h>
int main(void)
{
struct vertex *root = NULL;
long sample[] = { 6, 2, 3 };
enum { SIZE = sizeof(sample) / sizeof(sample[0]) };
for (int j = 0; j < SIZE; j++)
{
insert(&root, sample[j]);
}
clear_tree(&root);
return(0);
}
再次,在valgrind
下运行,我省略了大约20行valgrind
行政输出(没有相关内容):
-->> insert-1: (root 0x100AA94F0)
data 6; height 0; v = 0x100AA94F0, l = 0x000000000, r = 0x000000000, p = 0x000000000
<<-- insert-1:
-->> insert fixup 0: (root 0x100AA9560)
data 2; height 0; v = 0x100AA9560, l = 0x000000000, r = 0x000000000, p = 0x100AA94F0
<<-- insert fixup 0:
-->> insert fixup 3: (root 0x100AA94F0)
data 2; height 0; v = 0x100AA9560, l = 0x000000000, r = 0x000000000, p = 0x100AA94F0
data 6; height 1; v = 0x100AA94F0, l = 0x100AA9560, r = 0x000000000, p = 0x000000000
<<-- insert fixup 3:
-->> insert-2: (root 0x100AA94F0)
data 2; height 0; v = 0x100AA9560, l = 0x000000000, r = 0x000000000, p = 0x100AA94F0
data 6; height 1; v = 0x100AA94F0, l = 0x100AA9560, r = 0x000000000, p = 0x000000000
<<-- insert-2:
-->> insert fixup 0: (root 0x100AA95D0)
data 3; height 0; v = 0x100AA95D0, l = 0x000000000, r = 0x000000000, p = 0x100AA9560
<<-- insert fixup 0:
double left right rotating
-->> left_rotate: data 2; height 1; v = 0x100AA9560, l = 0x000000000, r = 0x100AA95D0, p = 0x100AA94F0
p is not NULL
p's l == v
LR1 - current node: data 2; height 1; v = 0x100AA9560, l = 0x000000000, r = 0x100AA95D0, p = 0x100AA94F0
LR1 - parent node: data 6; height 2; v = 0x100AA94F0, l = 0x100AA9560, r = 0x000000000, p = 0x000000000
LR1 - parent left: data 2; height 1; v = 0x100AA9560, l = 0x000000000, r = 0x100AA95D0, p = 0x100AA94F0
LR1 - current right: data 3; height 0; v = 0x100AA95D0, l = 0x000000000, r = 0x000000000, p = 0x100AA9560
-->> LR1 - tree from parent: (root 0x100AA94F0)
data 2; height 1; v = 0x100AA9560, l = 0x000000000, r = 0x100AA95D0, p = 0x100AA94F0
data 3; height 0; v = 0x100AA95D0, l = 0x000000000, r = 0x000000000, p = 0x100AA9560
data 6; height 2; v = 0x100AA94F0, l = 0x100AA9560, r = 0x000000000, p = 0x000000000
<<-- LR1 - tree from parent:
Assign (*v)->r (0x100AA95D0) to (*v)->p->l (0x100AA9560)
LR2 - current node: data 3; height 0; v = 0x100AA95D0, l = 0x000000000, r = 0x000000000, p = 0x100AA9560
LR2 - parent node: data 2; height 1; v = 0x100AA9560, l = 0x000000000, r = 0x100AA95D0, p = 0x100AA94F0
LR2 - parent left: data ; height ; v = 0x000000000
LR2 - current right: data ; height ; v = 0x000000000
-->> LR2 - tree from parent: (root 0x100AA9560)
data 2; height 1; v = 0x100AA9560, l = 0x000000000, r = 0x100AA95D0, p = 0x100AA94F0
data 3; height 0; v = 0x100AA95D0, l = 0x000000000, r = 0x000000000, p = 0x100AA9560
<<-- LR2 - tree from parent:
get there before
r == NULL
Assertion failed: ((*v)->r != NULL), function left_rotate, file AVL_tree.c, line 156.
==47909==
==47909== Process terminating with default action of signal 6 (SIGABRT)
==47909== at 0x100318032: __pthread_sigmask (in /usr/lib/system/libsystem_kernel.dylib)
==47909== by 0x100225774: __abort (in /usr/lib/system/libsystem_c.dylib)
==47909== by 0x1002256F5: abort (in /usr/lib/system/libsystem_c.dylib)
==47909== by 0x1001ECDF7: __assert_rtn (in /usr/lib/system/libsystem_c.dylib)
==47909== by 0x10000178A: left_rotate (AVL_tree.c:156)
==47909== by 0x100001EAC: insert (AVL_tree.c:189)
==47909== by 0x1000025B7: main (avl2.c:12)
我认为与此问题相关的是LR1和LR2输出线中当前节点的值:
LR1 - current node: data 2; height 1; v = 0x100AA9560, l = 0x000000000, r = 0x100AA95D0, p = 0x100AA94F0
…
LR2 - current node: data 3; height 0; v = 0x100AA95D0, l = 0x000000000, r = 0x000000000, p = 0x100AA9560
这两个都打印*v
,但它代表的节点已更改。追踪改变的原因,以及如何应对,可能会解决问题。
请注意调试技巧:
dump_vertex()
最初有assert(v != NULL)
,但是当我不想要它时会触发,所以现在它处理空指针。)我经常使用转储函数获取FILE *fp
参数,以便它们可以用于打印到任何文件。我通常也会在它们的末尾使用fflush(fp);
来确保将输出发送到文件流,即使程序在之后突然崩溃也是如此。因为我正在写入标准输出并且它没有被重定向,所以在这里不会造成麻烦 - 但最好在转储代码中执行此操作(这样可以省去我在这里打字,但是你应该知道为什么要这样做。
答案 1 :(得分:0)
我现在发现此代码的错误。右/左旋转功能使用指针指针。当我将父级的l或r指针传递给它时。它会导致函数内部出现错误。改进此代码的更好方法是通过指针替换指针指针,并通过返回值更新指针。