@Relike

Путаница в указателях?

Есть следующие функции
Three сreateThree(Node **q)
{
    if((*q)->p)
    {
        Three *one, *two;
        one = del(q);
        two = del(q);
        Three *t = new Three;
        t->left = one;
        t->right = two;
        t->weight = one->weight + two->weight;
 
        Node *tmpQ = 0;
 
        while(q)
        {
            Three *tmp;
            tmp = del(q);
            if(!tmpQ)
            {
                tmpQ = t->weight > tmp->weight ? first(tmp) : first(t);
            }
            else
            {
                t->weight > tmp->weight ? add(&tmpQ, tmp) : add(&tmpQ, t);
            }
        }
        сreateThree(&tmpQ);
    }
    else
    {
        return (*(*q)->t);
    }
}
 
Three* del(Node **pbeg)
{
    Three *temp = (*pbeg)->t; //ПОМЕЧЕННАЯ СТРОКА
    Node *pv = *pbeg;
    *pbeg = (*pbeg)->p;
    delete pv;
    return temp;
}
 
 
int main()
{
 
   /*НЕКИЙ РАБОТАЮЩИЙ КОД*/
 
    Node *q;
    formQueue(&q, values, symbols, count);
    Three t = сreateThree(&q);
    Show(&t);
 
    cout<<endl;
    return 0;
}

Вылетает ошибка Segmentation fault. Дебагер говорит что ошибка в помеченой строке. Видимо дело в указателях. Помогите разобраться

У меня тут две динамические структуры:

Three* createList(int weight, char symbol)
{
    Three *t = new Three;
    t->weight = weight;
    t->symbol = symbol;
    t->left = 0;
    t->right = 0;
}

Three* createList(int weight, char symbol)
{
    Three *t = new Three;
    t->weight = weight;
    t->symbol = symbol;
    t->left = 0;
    t->right = 0;
}

void Show(Three *t)
{
    if(t)
    {
        cout<<t->weight<<"\t"<<t->symbol<<endl;
        Show(t->left);
        Show(t->right);
    }
}

struct Node {
    Three *t;
    Node *p;
};

// Начальное формирование очереди
Node * first(Three *t)
{
    Node *pv = new Node;
    pv->t = t;
    pv->p = 0;
    return pv;
}
//---------------------------------------
// Добавление в конец
void add(Node **pend, Three *t)
{
    Node *pv = new Node;
    pv->t = t;
    pv->p = 0;
    (*pend)->p = pv;
    *pend = pv;
}
//---------------------------------------
// Выборка
Three* del(Node **pbeg)
{
    //assert(pbeg);
    //assert(*pbeg); //- Этот аассерт срабатывает и видимо сразу на первом вызове
    Three *temp = (*pbeg)->t;
    Node *pv = *pbeg;
    *pbeg = (*pbeg)->p;
    delete pv;
    return temp;
}


void sortArray(char *symbols, int *values, int count)
{
    int tmp_i;
    char tmp_c;

    for(int i = 0; i < count; i++)
    {
        for(int j = count-1; j > i; j--)
        {
            if(values[j-1] > values[j])
            {
                tmp_i = values[j];
                tmp_c = symbols[j];
                values[j] = values[j-1];
                symbols[j] = symbols[j-1];
                values[j-1] = tmp_i;
                symbols[j-1] = tmp_c;
            }
        }
    }
}


Функция formQoeue формирует очередь из деревьев на основе массива интов и строки:

void formQueue(Node **q, int *values, char *symbols, int count)
{
    Three *l = createList(values[0], symbols[0]);
    (*q) = first(l);
    Node *qEnd = (*q);
    for(int i = 1; i < count; i++)
    {
        Three *tmp = createList(values[i], symbols[i]);
        add(&qEnd, tmp);
    }
}


если сделать следующее:

while(q) Show(del(&q));
 return 0;


То будет всё отлично работать:

02b5259912f0446882a4ecbb3ffec52b.png

А вот в той функции всё пошло косо...я не знаю как быть...

8929e7325bae428489c964a2277f0680.png

Добавил ассерты
  • Вопрос задан
  • 215 просмотров
Решения вопроса 1
@monah_tuk
если pbeg == nullptr или *pbeg == nullptr, то (*pbeg)->t будет попыткой разыменования нулевого указателя, а то и двойной. Покажи ещё стек-трейс (команда bt в gdb), но вангую, что он приведёт к строчке:
two = del(q);
а в листе был всего 1 элемент.

Ванговал не правильно, но близко:
Если вы опубликовали правильный код, тот который реально у вас. У вас проблемы. Причём не только с указателями:
1. createList не возвращает созданный t - на выходе будете иметь мусор
2. не могу чётко уловить логику, но createThree тоже может в определённых условиях вернуть мусор. Судя по всему внутри должен быть не просто рекурсивный вызов:
createThree(&tmpQ);
а:
return createThree(&tmpQ);
3. касательно указателей, просмотрел, но вот этот код никогда не закончится:
while(q) {
потому как q ни когда не станет null, а вот *q может и становится и собственно в таком виде и передаётся в del() в строчке tmp = del(q); в результате и получаешь фейл.

дальше у тебя там ещё, походу, баг в логике. Но это уже без меня.

PS если не поможет - приведите минимально-работающий код, на котором воспроизводится проблема.
PPS у вас C++, уйдите от указателей на указатели, используйте ссылки, например:
Three* del(Node &*pbeg)
{
    assert(pbeg != 0); // для гарантий
    Three *temp = pbeg->t; //ПОМЕЧЕННАЯ СТРОКА
    Node *pv = pbeg;
    pbeg = pbeg->p;
    delete pv;
    return temp;
}

И вообще, в C++: попытайтесь заменить указатели на ссылки везде где это только можно. Много нервов сбережёте.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы