Двоичное дерево поиска в C, вызывающее ошибку повреждения кучи

Итак, я программист на Python, и я пытаюсь выучить C. Просто в качестве практики я пытался реализовать простое двоичное дерево поиска на C. Мне никогда раньше не приходилось работать с распределением памяти или указателями и это вызвало много ошибок.

Моя программа давала мне код выхода -1073740940 (0xC0000374), который, как я понимаю, означает, что куча повреждена. Это немного длинная программа, поэтому я просто включил функцию, вызывающую нарушение.

Эта функция вставки многократно вызывается с использованием цикла for для вставки содержимого массива в двоичное дерево поиска. Содержимое массива: 5, 4, 6, 3, 7, 2, 8, 1, 9 и 0 (предназначено для сбалансированного дерева).

Таким образом, функция сначала имеет 5 переданных ей. Указатель, вызываемый pBST->listRoot, равен NULL (pBST — это указатель на структуру списка), поэтому вставьте 5 в качестве корневого узла. Это прекрасно работает. Затем в функцию передается 4. Поскольку корень уже есть, он проверяет дочерние элементы этого корня. 4 меньше 5, поэтому проверьте левого потомка 5. Указатель на левый дочерний элемент 5 равен нулю, поэтому он пытается вставить 4 в качестве нового узла. Это строка, которая приводит к сбою программы:

struct Node* pTemp = calloc(1, sizeof(struct Node));

Я пробовал несколько вариантов этой линии. Вот в чем проблема: отладчик cLion не может это воспроизвести. Когда я запускаю его через отладчик, он работает отлично. Я думаю, это связано с тем, что отладчик каждый раз использует одни и те же адреса памяти для воспроизводимости. Я оставил операторы отладки printf и добавил код для структур Node и binarySearchTree.

typedef struct Node BSTNode;

struct Node {
    BSTNode* parent;
    BSTNode* left;
    BSTNode* right;
    int* data;
};



typedef struct {
    BSTNode* listRoot;
    int nodeCount;
} binarySearchTree;
void insert(int Value, binarySearchTree* pBST) {
/*
 * This function
 */

//====DEBUG CODE============
int debugIterations = 0;
printf("Now inserting %d \n", Value);
//=====END DEBUG CODE=======


//if no root, make it the root
if (pBST->listRoot == NULL) {

    struct Node* newNode = calloc(1, sizeof(binarySearchTree));
    (*pBST).listRoot = newNode;

    (*pBST).listRoot->data;

    (*pBST).listRoot->data = Value;
    //pBST->listRoot->data = Value;

    pBST->listRoot->parent = NULL;

    pBST->listRoot->right = NULL;
    pBST->listRoot->left = NULL;

    return;
} else {
    struct Node* pCursor = pBST->listRoot;

    while (1){

        printf("Iterations: %d \n", debugIterations);
        debugIterations++;


        //Check if the number is the same
        if (pCursor->data == Value){
            printf("ERROR: Tried to insert duplicate value into tree");
            return;
        }

        //Is the value > the node?
        else if (pCursor->data < Value) {

            //DEBUG
            printf("== check succeeded, now value > data\n");


            // Is the value a Null?
            if (pCursor->right == NULL) {

                //DEBUG
                printf("Running function to insert %d as a new node to the right\n", Value);

                //If yes, then insert the value as a nul

                //Create Node
                struct Node* pTemp = calloc(1, sizeof(binarySearchTree));
                pTemp->data = Value;
                pTemp->parent = pCursor;
                pCursor->right = pTemp;
                pTemp->left = NULL;
                pTemp->right = NULL;

                return;
            }

            //If no, then iteravely continue.
            else {

                printf("Iteravely continuing to the right");

                pCursor = pCursor->right;
                continue;
            }

        }

        //Is the value < the root?
        else {

            //DEBUG
            printf("== check succeeded, now value < data\n");



            //Is the value a Null?
            if (pCursor->left == NULL) {

                //DEBUG
                printf("Running function to insert %d as a new node to the left\n", Value);




                //If yes, then insert the value where the null is.
                //Create Node

                struct Node* pTemp = (struct Node*)calloc(1, sizeof(struct Node));

                printf("Successfully declared and allocated memory");

                pTemp->data = Value;
                pTemp->parent = pCursor;
                pCursor->left = pTemp;
                pTemp->left = NULL;
                pTemp->right = NULL;

                return;
            }

            //If no, then iteravely continue
            else{

                printf("Iteravely continuing to the right");

                pCursor = pCursor->left;
                continue;
            }

        }

    }

}

}


person mrj9797    schedule 21.05.2021    source источник
comment
struct Node* newNode = calloc(1, sizeof(binarySearchTree)); кажется странным, разве это не sizeof(Node)?   -  person 500 - Internal Server Error    schedule 21.05.2021
comment
Стоит отметить, что GeeksForGeeks имеет обширную обработку бинарных деревьев с исходным кодом, так что вы можете сравнивать записи. geeksforgeeks.org/binary-tree-data-structure   -  person Robert Harvey    schedule 21.05.2021
comment
Разве вы не получаете предупреждение компилятора с одинокой строкой (*pBST).listRoot->data; ? Я предлагаю вам удалить это...   -  person Zilog80    schedule 21.05.2021


Ответы (1)


Линия

struct Node* pTemp = calloc(1, sizeof(binarySearchTree));

неправильно. Структура binarySearchTree имеет один указатель и один int, а структура struct Node имеет 4 указателя, поэтому struct Node должно быть больше, чем binarySearchTree, и это распределение будет выделять меньше места, чем требуется, что приведет к доступу за пределами допустимого диапазона.

Так должно быть:

struct Node* pTemp = calloc(1, sizeof(*pTemp));

or

struct Node* pTemp = calloc(1, sizeof(struct Node));

Также выглядит очень странно хранить данные int Value в члене int* data; с (*pBST).listRoot->data = Value;. Похоже, член должен быть int, а не int*.

person MikeCAT    schedule 21.05.2021
comment
Или BSTNode* вместо struct Node* - person Robert Harvey; 21.05.2021
comment
Спасибо за помощь. К сожалению, я исправил это, и это ничего не сделало. Программа все равно вылетает. - person mrj9797; 21.05.2021
comment
Мои два цента: должно быть struct Node* pTemp = calloc(1, sizeof(struct Node));. Зарезервируйте место для узла, а не для указателя узла. - person Zilog80; 21.05.2021
comment
@ Zilog80 Спасибо, исправлено. - person MikeCAT; 21.05.2021