Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.57/7: Рейтинг темы: голосов - 7, средняя оценка - 4.57
2 / 2 / 0
Регистрация: 15.05.2019
Сообщений: 110
1

Необходимость указателя на указатель

03.06.2020, 14:19. Показов 1275. Ответов 15
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Добрый день.
Не могу разобраться, подскажите пожалуйста для чего в нижеприведенном методе(занесение узлов в двоичное дерево) используется указатель на указатель.
Разве тут нельзя обойтись просто передачей указателя?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
template<typename NODETYPE>
void Tree<NODETYPE>::insertNodeHelper(TreeNode<NODETYPE> **ptr, const NODETYPE &value)
{
   if (*ptr==nullptr)
   {
      *ptr=new TreeNode<NODETYPE>(value);
   }
   else
   {
      if (value < (*ptr)->data)
      {
         insertNodeHelper( &( (*ptr)->leftPtr), value);
      }
      else
      {
         if (value > (*ptr)->data)
         {
            insertNodeHelper(& ( (*ptr)->rightPtr), value);
         }
         else
         {
            //cout<<value<<" dup"<<endl;
         }
      }
   }
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
03.06.2020, 14:19
Ответы с готовыми решениями:

Сохранить адрес из указателя в другой указатель, а потом первый указатель удалить
Добрый день всем. Возмём простейший пример: #include &lt;iostream&gt; using namespace std; int...

Передача умного указателя в функцию принимающую указатель на указатель
Итак имеется функция со следующим параметром: HRESULT __stdcall Function(SomeClass **param); ...

Разыменование указателя на указатель
в функцию передается указатель на указатель класса, что бы получить доступ к методам класса нужно...

Инкремент указателя на указатель
Добрый день!!! Ребят, подскажите пожалуста, как выполнить инкремент указателя на указатель....

15
18834 / 9836 / 2405
Регистрация: 30.01.2014
Сообщений: 17,273
03.06.2020, 14:39 2
dm_Consul, Ссылка на указатель. Проблема

Добавлено через 54 секунды
Особенно это.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
03.06.2020, 14:41 3
Цитата Сообщение от dm_Consul Посмотреть сообщение
Разве тут нельзя обойтись просто передачей указателя?
нельзя.

функция изменяет значение указателя:
Цитата Сообщение от dm_Consul Посмотреть сообщение
*ptr=new TreeNode<NODETYPE>(value);
если бы функция принимала "просто указатель",
тогда внутри функции фигурировала бы копия указателя.

и функция изменила бы значение копии, а не оригинала.

что бы изменить значение оригинального указателя,
нормальные люди используют ссылку-на-указатель.

аморальные люди используют указатель-на-указатель.

твой код писал аморальный человек.
0
Эксперт CЭксперт С++
5113 / 4552 / 854
Регистрация: 07.10.2015
Сообщений: 9,462
03.06.2020, 14:42 4
dm_Consul, если сказать просто: чтобы можно было изменить этот указатель в вызывающем модуле.
0
2 / 2 / 0
Регистрация: 15.05.2019
Сообщений: 110
03.06.2020, 15:00  [ТС] 5
Цитата Сообщение от hoggy Посмотреть сообщение
твой код писал аморальный человек
Это из учебника Дейтлов. (Как программировать на с++)

Понятно что передается копия указателя. Но разве она не указывает на тоже значение, и соответственно не меняет его?
0
18834 / 9836 / 2405
Регистрация: 30.01.2014
Сообщений: 17,273
03.06.2020, 15:04 6
Цитата Сообщение от dm_Consul Посмотреть сообщение
Но разве она не указывает на тоже значение, и соответственно не меняет его?
А вы прочитайте по ссылке выше и все станет понятно.
1
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
03.06.2020, 15:11 7
Цитата Сообщение от dm_Consul Посмотреть сообщение
Понятно что передается копия указателя. Но разве она не указывает на тоже значение, и соответственно не меняет его?
тебе нужно внимательнее читать аморальный учебник аморальных Дейтлов.

давай поступим так:
задача: изменить значение самого указателя,
а не того объекта, на который он указывает.

рассмотрим простейший пример:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
 
int a = 10;
int b = 20;
 
int main()
{
    int* p = &a; // <--- указывает на объект 'a'
    foo(p);
 
    // <--- здесь указатель уже должен быть перенацелен на объект 'b'
 
    std::cout << *p ; // <--- должен напечатать в консоль число 20
}
напиши функцию foo, которая на входе получит указатель,
и перенацелит его на объект b

в консоль должно напечататься значение переменной b


если решишь эту задачу, тогда поймёшь зачем нужны ссылки-на-указатели,
ну или указатели-на-указатели, как это сделал аморальный Дейтл.
1
172 / 91 / 36
Регистрация: 22.05.2020
Сообщений: 308
03.06.2020, 15:41 8
Кстати, в чём преимущество функции
C++
1
void F(TreeNode<NODETYPE> **ptr, const NODETYPE &value)
перед функцией
C++
1
TreeNode<NODETYPE>* F(TreeNode<NODETYPE> *pnode, const NODETYPE &value)
?
0
2 / 2 / 0
Регистрация: 15.05.2019
Сообщений: 110
03.06.2020, 15:45  [ТС] 9
Цитата Сообщение от DrOffset Посмотреть сообщение
А вы прочитайте по ссылке выше и все станет понятно.
Цитата Сообщение от hoggy Посмотреть сообщение
давай поступим так:
задача: изменить значение самого указателя,
а не того объекта, на который он указывает.
Немного разобрался, спасибо.
0
Вездепух
Эксперт CЭксперт С++
11691 / 6370 / 1723
Регистрация: 18.10.2014
Сообщений: 16,053
03.06.2020, 17:28 10
Цитата Сообщение от valker Посмотреть сообщение
Кстати, в чём преимущество функции
C++
1
void F(TreeNode<NODETYPE> **ptr, const NODETYPE &value)
перед функцией
C++
1
TreeNode<NODETYPE>* F(TreeNode<NODETYPE> *pnode, const NODETYPE &value)
?
Можно было поступить и так. Однако в таком варианте при реализации рекурсивной insertNodeHelper нам бы пришлось присваивать результат работы функции на каждом уровне рекурсии. А это расточительно, ибо фактическое изменение указателя происходит только на самом нижнем уровне.
0
"C with Classes"
1646 / 1403 / 523
Регистрация: 16.08.2014
Сообщений: 5,877
Записей в блоге: 1
03.06.2020, 18:00 11
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
А это расточительно, ибо фактическое изменение указателя происходит только на самом нижнем уровне.
а как сделать не расточительно?
0
Вездепух
Эксперт CЭксперт С++
11691 / 6370 / 1723
Регистрация: 18.10.2014
Сообщений: 16,053
03.06.2020, 18:12 12
Цитата Сообщение от _stanislav Посмотреть сообщение
а как сделать не расточительно?
Вот именно передача указателя на указатель (или ссылки на указатель) через параметры - это, возможно, и есть попытка сделать "не расточительно".

То есть таким способом, вместо выполнения безусловного присваивания на каждом уровне рекурсии, автор делает "отложенное присваивание": левая часть присваивания передается "по ссылке" и физическое присваивание делается только в тот момент, когда оно действительно нужно. В данном примере - один раз по достижении листа дерева.

В рамках данной задачи овчинка может не стоить выделки, а вот в случае более тяжелых объектов - это стандартный паттерн.
1
172 / 91 / 36
Регистрация: 22.05.2020
Сообщений: 308
04.06.2020, 00:48 13
TheCalligrapher, однако, если в случае возврата значения из указателя у компилятора есть возможность соптимизировать и вернуть значение в регистре, то при необходимости записать значение в память, её-таки придётся записать, а это не всегда быстро.
0
Вездепух
Эксперт CЭксперт С++
11691 / 6370 / 1723
Регистрация: 18.10.2014
Сообщений: 16,053
04.06.2020, 06:19 14
Цитата Сообщение от valker Посмотреть сообщение
однако, если в случае возврата значения из указателя у компилятора есть возможность соптимизировать и вернуть значение в регистре, то при необходимости записать значение в память, её-таки придётся записать, а это не всегда быстро.
В моем сообщении №10 речь идет о том, что если данную рекурсивную функцию переделать на

C++
1
TreeNode<NODETYPE>* F(TreeNode<NODETYPE> *pnode, const NODETYPE &value)
то не первый взгляд рекурсивные вызовы тогда будут выглядеть так

C++
1
2
3
  pnode->leftPtr = insertNodeHelper(pnode->leftPtr, value);
  ...
  pnode->rightPtr = insertNodeHelper(pnode->rightPtr, value);
То есть нам мало просто получить новое значение указателя (пусть даже и в регистере), нам нужно еще помнить о том, что это новое значение указателя необходимо записать в предка узла, то есть записать его из регистра в память (!). Причем в таком варианте запись делается на каждом уровне рекурсии. И это при том, что на большинстве уровней рекурсии значение указателя меняться не будет, то есть запись в память совсем не нужна. Вот об этом я и виду речь.

То есть в этом случае запись в память тоже есть. Причем не просто "есть", а есть во множественном (и избыточном!) количестве.

Если вы можете предложить способ организации рекурсивных вызовов для

C++
1
TreeNode<NODETYPE>* F(TreeNode<NODETYPE> *pnode, const NODETYPE &value)
свободный от этого недостатка - давайте, предлагайте.
0
172 / 91 / 36
Регистрация: 22.05.2020
Сообщений: 308
04.06.2020, 10:34 15
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
свободный от этого недостатка - давайте, предлагайте.
Вариантов может быть несколько. Например такой:
1. Возвращаем указатель на новый объект, если он создан через new. В противном случае возвращаем nullptr.
2. В вызывающем проверяем указатель, и если он не равен nullptr, сохраняем "в памяти".
0
Вездепух
Эксперт CЭксперт С++
11691 / 6370 / 1723
Регистрация: 18.10.2014
Сообщений: 16,053
04.06.2020, 10:49 16
Цитата Сообщение от valker Посмотреть сообщение
Вариантов может быть несколько. Например такой:
1. Возвращаем указатель на новый объект, если он создан через new. В противном случае возвращаем nullptr.
2. В вызывающем проверяем указатель, и если он не равен nullptr, сохраняем "в памяти".
Это создает дополнительно ветвление для проверки на nullptr, что тоже требует затрат производительности.

Смотрим ваше исходное замечание

Цитата Сообщение от valker Посмотреть сообщение
то при необходимости записать значение в память, её-таки придётся записать, а это не всегда быстро.
Но "запись в память" там делается только один раз: в самом листовом узле дерева, при создании нового узла. То есть запись в память там делается ровно и только в том случае, что и в предлагаемом вами варианте. Но в предлагаемом вами варианте нужно дополнительное ветвление в вызывающем коде, а в исходном варианте все ветвления уже и так сделаны и дополнительного ветвления не нужно.
0
04.06.2020, 10:49
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
04.06.2020, 10:49
Помогаю со студенческими работами здесь

Передача в функцию указателя на указатель
Добавление нового элемента в начало списка: void Add_Beg(List **u, Data &amp;x) // Почему в 1...

Передача указателя на указатель в функцию
Вопрос к знатокам: Есть абстрактный класс(Symbol) и его производный (Cross). Создаю указатель этого...

вызов метода у указателя на указатель на класс
Доброго времени суток! Простите за, возможно, глупый вопрос и/или его неточную формулировку, но...

Указатель на объект из указателя на член класса
Что как-то сей вопрос ставит меня в тупик. class A { int i; } obj; int main()

Сохранение/Загрузка указателя на указатель типа char
char **data = new char*; Подскажите, пожалуйста, как записать содержимое всего выше...

Передача в функцию указателя на указатель на одномерный массив
Как изменить следующий код, чтобы в функции addValue в качестве первого входного параметра...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru