Я пытаюсь реализовать обход Inorder, который возвращает массив с пройденными значениями. В моем рекурсивном подходе я пытаюсь использовать функцию realloc(), чтобы изменить размер массива и сохранить результат. Однако я получаю следующую ошибку:

realloc(): invalid next size .

Ниже приведен мой код:

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

void inorder(struct TreeNode *root, int *res, int *returnSize)
{
    if(root == NULL)
        return;

    //if left node present, traverse left
    inorder(root->left,res,returnSize);

    // add node to array
    res[(*returnSize)]=root->val;
    (*returnSize)++;
    int *temp = realloc(res,sizeof(int)*(*returnSize)); 
    res = temp;

    //if right node present, traverse right
    inorder(root->right,res,returnSize);
}

/**
 * Return an array of size *returnSize.
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* inorderTraversal(struct TreeNode* root, int* returnSize) 
{
    //check if root == null
    if(root == NULL)
    {
        return root;
    }

    //malloc result array to return
    int *res = (int *)malloc(sizeof(int)*(*returnSize));

    //start inorder parsing
    inorder(root, res, returnSize);

    return res;
}
0
chandana 21 Окт 2017 в 04:53

3 ответа

Лучший ответ

Есть несколько проблем:

  • перераспределенное значение для res не передается вызывающей стороне. Вы должны передать указатель на res вместо его значения или вернуть вновь выделенный указатель.
  • returnSize - выходная переменная, вы должны инициализировать ее 1 или, что лучше, 0 и перераспределить массив перед сохранением значения узла.
  • Вы должны обрабатывать потенциальные ошибки выделения памяти.

Вот исправленная версия:

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

int *inorder(struct TreeNode *root, int *res, int *returnSize) {
    if (root != NULL) {
        //traverse the left tree
        res = inorder(root->left, res, returnSize);

        if (returnSize >= 0) {
            // add node to array
            int *temp = realloc(res, sizeof(int) * (*returnSize) + 1); 
            if (temp == NULL) {
                free(res);
                *returnSize = -1;
                res = NULL;
            } else {
                res = temp;
                res[(*returnSize)++] = root->val;

                //traverse the right tree
                res = inorder(root->right, res, returnSize);
            }
        }
    }
    return res;
}

/**
 * Return an array of size *returnSize.
 * Return NULL and *returnSize=0 for an empty tree.
 * Return NULL and *returnSize<0 for memory allocation failure.
 * Note: The returned array is malloced, the caller must call free().
 */
int *inorderTraversal(struct TreeNode *root, int *returnSize) {
    int *res = NULL;

    *returnSize = 0;
    return inorder(root, res, returnSize);
}
1
chqrlie 21 Окт 2017 в 12:23

У вас почти наверняка есть повреждения памяти в другом месте вашего кода - этот код выглядит хорошо для меня (хорошо, если не проверять возврат из realloc () для NULL, но это просто приведет к потере данных, а не к полученной вами ошибке) видя ) . Если вы можете запустить valgrind в своей программе, это, вероятно, укажет вам на проблему.

0
Jabberwock 21 Окт 2017 в 02:37

Немного времени, но я надеюсь, что вы терпеливы ... :) Причины перезапуска в вашей программе 3:

  1. Реал realloc работает + правила области, следовательно: realloc попытается выделить необходимое пространство, но может не вернуть тот же адрес, что и указатель, который вы указали, и в вашем коде эти изменения (если они произойдут) будут влиять только на значения res в области функций, и те, которые вы передаете в качестве аргументов (только «вниз»), поэтому, как только вы спуститесь вниз, левая ветвь присвоит значение последнему узлу и начнет подниматься, так сказать, используемый вами адрес может уже были освобождены, и это не правильный указатель.

  2. Как упоминалось ранее, проверка того, что вызов realloc был успешным, имеет решающее значение. Возьмите случай, что это не было; в этом случае старый сегмент памяти и указатель останутся нетронутыми, и, присваивая невыполненное возвращаемое значение res без проверки, вы фактически удаляете указатель на этот кусок памяти и не сможете его освободить.

  3. Убедитесь, что начальная выделенная память не равна нулю (по крайней мере, 1), потому что если она равна 0, вы присваиваете значение за пределами вашего массива (выделенная память была 0).

                           //res was changed to a int **  <<<-----
void inorder(struct TreeNode *root,int ** res,  int *returnSize){
        if(root == NULL)
                return;
    //if left node present traverse left
        inorder(root->left, res, returnSize);
        puts("traversed left");
    // add node to array
    //here i dereferenced res since now it is an int **, and subtracted 1 
    //from returnSize -> arrays indexes starting from 0 
        (*res)[(*returnSize)-1] = root->val;

        (*returnSize)++;
        printf("res: %p \n", *res);//just so you can see the address before
        int * temp = realloc(*res, sizeof(int) * (*returnSize));
        printf("temp: %p \n", temp);//and after
        //making sure that realloc was successful
        if(temp == NULL){
                temp = *res;//we do not want to lose our previous pointer in case it was not...
        }
        *res = temp;
        inorder(root->right, res, returnSize);
}

/**
 * Return an array of size *returnSize.
 * Note: The returned array must be malloced, assume caller calls free().
*/
int* inorderTraversal(struct TreeNode* root, int* returnSize) 
{
    //check if root == null
    if(root == NULL)
    {
    return root;
    }

    //malloc result array to return
    int *res = (int *)malloc(sizeof(int)*(*returnSize));

    //start inorder parsing
    //and here you pass the address of res <<<-----
    inorder(root, &res, returnSize);

    return res;
}
0
Jonathan Leffler 21 Окт 2017 в 16:34