为什么这两个C指针在一行代码后设置为NULL?

时间:2016-01-23 04:27:02

标签: c

以下是我以前从未见过并且从未见过的代码。 只有一行代码更改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);
}

}

2 个答案:

答案 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, 16, 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指针传递给它时。它会导致函数内部出现错误。改进此代码的更好方法是通过指针替换指针指针,并通过返回值更新指针。