@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

Добавил ассерты
  • Вопрос задан
  • 216 просмотров
Решения вопроса 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++: попытайтесь заменить указатели на ссылки везде где это только можно. Много нервов сбережёте.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Похожие вопросы