Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
30 / 7 / 0
Регистрация: 20.02.2016
Сообщений: 1,241
1

Почему Лафоре использует указатели на указатели, вместо обмена значениями указателей?

17.10.2018, 20:59. Показов 1045. Ответов 25
Метки нет (Все метки)

Доброго времени суток!
Задался теоретическим вопросом. Читал пример из книги Лафоре ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ
ПРОГРАММИРОВАНИЕ В C++, код persort.cpp// сортировка объектов через массив указателей на них. Рассматривается массив указателей на объекты. Автор пишет, что быстрее рассортировать в массиве сами указатели через указатели на них, потому что
"Таким образом мы исключаем необходимость перемещения объектов в памяти, которое отнимает много времени, если объекты очень большие" . То есть идёт работа с указателями на указатели. Я не понимаю, почему нельзя просто менять
значения адресов, которые хранятся в указателях, одно значение записывать в один указатель, а его первоначальное
значение- в другой. Ключевым ведь является то, что если я поменяю в указателе значение - адрес объекта, это же не значит
что тот объект, на который данный указатель указывал, переместиться на этот этот новый адрес
(как процитировано выше), правильно ? Или я чего-то не понимаю? Код из книги ниже, но зачем же усложнять указателями на указатели?


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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>
#include <string>                 //for string class
using namespace std;             
 
class person                      //class of persons
   {
   protected:
      string name;                //person's name
   public:
      void setName()              //set the name
         { cout << "Enter name: "; cin >> name; }
      void printName()            //display the name
         { cout << endl << name; }
      string getName()            //return the name
         { return name; }
   };
 
int main()
   {
   void bsort(person**, int);     //prototype
   person* persPtr[100];          //array of pointers to persons
   int n = 0;                     //number of persons in array
   char choice;                   //input char
          
   do {                           //put persons in array
      persPtr[n] = new person;    //make new object
      persPtr[n]->setName();      //set person's name
      n++;                        //count new person
      cout << "Enter another (y/n)? "; //enter another
      cin >> choice;              //   person?
      }
   while( choice=='y' );          //quit on 'n'
 
   cout << "\nUnsorted list:";
   for(int j=0; j<n; j++)         //print unsorted list
      { persPtr[j]->printName(); }     
 
   bsort(persPtr, n);             //sort pointers
 
   cout << "\nSorted list:";
   for(j=0; j<n; j++)             //print sorted list
      { persPtr[j]->printName(); }
   cout << endl;
   return 0;
   }  //end main()
 
void bsort(person** pp, int n)    //sort pointers to persons
   {                              
   void order(person**, person**);  //prototype
   int j, k;                      //indexes to array
 
   for(j=0; j<n-1; j++)           //outer loop
      for(k=j+1; k<n; k++)        //inner loop starts at outer
          order(pp+j, pp+k);       //order the pointer contents
   }
 
void order(person** pp1, person** pp2)  //orders two pointers
   {                              //if 1st larger than 2nd,
   if( (*pp1)->getName() > (*pp2)->getName() )
      {
      person* tempptr = *pp1;     //swap the pointers
      *pp1 = *pp2;
      *pp2 = tempptr;
      }
   }
__________________
Помощь в написании контрольных, курсовых и дипломных работ здесь
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
17.10.2018, 20:59
Ответы с готовыми решениями:

Массивы указателей и указатели на указатели
В чем разница между массивами указателей и указателями на указатели? Может, между ними такая же...

Указатели на указатели с числами. Почему можно присвоить число в 4-ый элемент, если массив из 2 элементов?
Есть массив int **mas; mas=new int*; // выделил место под пять строк, верно ? mas=new int;//...

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

Указатели и указатели на указатели, а также типы данных
Недавно начал изучать Си, перешел с Delphi. Много непонятного и пока процесс идет медленно....

25
0 / 1 / 0
Регистрация: 12.10.2018
Сообщений: 10
17.10.2018, 21:38 2
Попробую объяснить, хотя я не опытный. Вы хотите заменить тип person ** на person*.
Тут надо хорошо понимать указатели. Проблема в том, что в функцию указатели передаются по значению(её копии). То есть, если вы сделаете вот так:
C++
1
2
3
4
5
6
void order(person* p1, person* p2)  //orders two pointers
{                              //if 1st larger than 2nd,
person * tmp=p1;
p1=p2;
p2=tmp;
}
Вы на самом деле измените не значения ОРИГИНАЛЬНЫХ указателей, а его копий. Передавая же тип (person **) - вы получаете доступ к значению оригинального указателя с помощью оператора разыменования(*):
C++
1
2
3
4
5
6
void order(person** p1, person** p2)  //orders two pointers
{                              //if 1st larger than 2nd,
person ** tmp=*p1;
*p1=*p2;
*p2=*tmp;
}
0
30 / 7 / 0
Регистрация: 20.02.2016
Сообщений: 1,241
17.10.2018, 21:44  [ТС] 3
alexbez, то есть смысл в том, чтобы во время сортировки задействовать меньше памяти, не создавая копии?
А если всё же , даже если, использовать копии, как в первом коде, объекты будут перемещаться в памяти, как пишет Лафоре? я так понимаю, что нет.
0
0 / 1 / 0
Регистрация: 12.10.2018
Сообщений: 10
17.10.2018, 21:57 4
Fatmarmelad, возможно я поторопился с ответом. Увидел дату вашей регистрации, после того как написал ответ. Я думал это вопрос от новичка. Наверно я что-то не то написал. Извините.
0
30 / 7 / 0
Регистрация: 20.02.2016
Сообщений: 1,241
17.10.2018, 23:24  [ТС] 5
alexbez, я и есть новичок. С++ учу в свободное время. Поэтому и спрашиваю. Меня заинтересовало, почему Лафоре пишет про перемещение объектов в памяти.
0
1028 / 710 / 316
Регистрация: 26.02.2015
Сообщений: 3,225
17.10.2018, 23:27 6
Fatmarmelad, ну, так а ты попробовал запустить программу без указателей на указатели?

Добавлено через 33 секунды

Не по теме:

Цитата Сообщение от alexbez Посмотреть сообщение
Fatmarmelad, возможно я поторопился с ответом. Увидел дату вашей регистрации, после того как написал ответ. Я думал это вопрос от новичка. Наверно я что-то не то написал. Извините.
Ты что, мямля?

0
1362 / 999 / 316
Регистрация: 28.07.2012
Сообщений: 2,764
17.10.2018, 23:40 7
Fatmarmelad, все довольно просто. В случае обычной сортировки имеется массив элементов типа T=person. Указатель на элемент этого массива будет иметь тип T *=person *.
В твоем же случае у тебя массив элементов типа T=person *. Тогда указатель на элемент этого массива будет иметь тип T *=person **. Вот отсюда и берется двойной указатель.

Вся суть подхода в том, чтобы избежать дорогостоящего копирования элементов массива. Обмен местами двух элементов типа T=person может занимать на порядок больше времени, чем обмен двух элементов типа T=person *.
0
15248 / 8216 / 1992
Регистрация: 30.01.2014
Сообщений: 13,998
18.10.2018, 01:43 8
alexbez, вы верно в целом все описали.

Цитата Сообщение от Fatmarmelad Посмотреть сообщение
Код из книги ниже, но зачем же усложнять указателями на указатели?
В данном случае это не усложнение, а обоснованное действие. Вы не сможете поменять местами содержимое двух указателей без этой дополнительной косвенности.

Возьмите и замените тип указателя на обычный int.
C++
1
2
3
4
5
6
void swap(int * a, int * b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
А теперь нам надо поменять местами значение двух указателей на int, вместо двух int`ов. Получаем:
C++
1
2
3
4
5
6
void swap(int ** a, int ** b)
{
    int * tmp = *a;
    *a = *b;
    *b = tmp;
}
Добавлено через 5 минут
Fatmarmelad, Единственное, что здесь нужно знать про указатели, что int * - это такой тип.

Вы, если не понимаете как это так, пишите функцию с условным T (как вам выше объяснили), а потом меняйте T на тот тип, который нужен. Вот общая функция обмена местами значений двух переменных:
C++
1
2
3
4
5
6
void swap(T * a, T * b)
{
   T tmp = *a;
   *a = *b;
   *b = tmp;
}
Если вы вместо T подставите int (т.е. таким образом нас интересует обмен значений двух переменных типа int), то получите первую функцию из моего примера.
Если подставите вместо T тип int * (т.е. таким образом нас интересует обмен значений двух переменных типа указатель на int), то получите функцию из второго примера, и примерно тоже самое, что было дано в книге.
0
Нарушитель
3063 / 1670 / 578
Регистрация: 23.09.2014
Сообщений: 5,199
18.10.2018, 08:34 9
Цитата Сообщение от Fatmarmelad Посмотреть сообщение
Меня заинтересовало, почему Лафоре пишет про перемещение объектов в памяти.
Лафоре предлагает сортировать не массив объектов, а массив указателей на эти объекты.
Почему?
Представьте что у вас есть фильмотека из 1000 фильмов и вы решили упорядочить их по году выхода.
Вы предпочтете физически разложить их в своем каталоге по выбранному критерию или все же предпочтете составить таблицу указателей на эти файлы?
0
Эксперт С++
8555 / 4131 / 908
Регистрация: 15.11.2014
Сообщений: 9,329
18.10.2018, 12:48 10
Цитата Сообщение от XLAT Посмотреть сообщение
Вы предпочтете физически разложить их в своем каталоге по выбранному критерию или все же предпочтете составить таблицу указателей на эти файлы?
я предпочту std::map, Бро.
0
Заблокирован
18.10.2018, 14:40 11
Цитата Сообщение от hoggy Посмотреть сообщение
я предпочту std::map
он же медленный
0
30 / 7 / 0
Регистрация: 20.02.2016
Сообщений: 1,241
18.10.2018, 21:23  [ТС] 12
Я задался этой темой из-за слов, которые привёл выше
"Таким образом мы исключаем необходимость перемещения объектов в памяти, которое отнимает много времени, если объекты очень большие" .
Сейчас я понимаю, что массив объектов в функции это Class*, а массив указателей на них Class**. Иначе записать нельзя.
C++
1
void func(Class**, int);
Добавлено через 24 минуты
Вдогонку. Насколько я сейчас понимаю, невозможно поменять значения адресов элементов массива, потому что они -константы. Прав ли я? То есть код ниже невозможен.

C++
1
2
3
temp = &arr[1];
&arr[1]=&arr[2];
&arr[2]=temp;
0
Нарушитель
3063 / 1670 / 578
Регистрация: 23.09.2014
Сообщений: 5,199
19.10.2018, 01:06 13
Цитата Сообщение от Fatmarmelad Посмотреть сообщение
void func(Class**, int);
можно так:
C++
1
void func(Class* m[], int);
Цитата Сообщение от Fatmarmelad Посмотреть сообщение
То есть код ниже невозможен.
да, невозможен.
Представь ячейку памяти в своем компе, которая что-то хранит.
У неё есть номер. Он же и адрес.
0
Don't worry, be happy
17205 / 10083 / 1945
Регистрация: 27.09.2012
Сообщений: 25,158
Записей в блоге: 1
19.10.2018, 10:21 14
можно так
И в чем разница?
0
3362 / 1914 / 368
Регистрация: 09.09.2017
Сообщений: 7,793
19.10.2018, 10:47 15
В том, что передается массив указателей, а не указатель на указатель. Такая запись может служить подсказкой программисту.
1
Don't worry, be happy
17205 / 10083 / 1945
Регистрация: 27.09.2012
Сообщений: 25,158
Записей в блоге: 1
19.10.2018, 10:52 16
COKPOWEHEU, передается в обоих случаях указатель на указатель и первая запись лучше отражает тип переменной.
0
3362 / 1914 / 368
Регистрация: 09.09.2017
Сообщений: 7,793
19.10.2018, 11:11 17
Croessmah, хорошо, давайте я повторю ключевую фразу:
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Такая запись может служить подсказкой программисту.
Разумеется, с точки зрения языка эти записи эквивалентны. Но вы же не будете писать код в одну строчку только потому что компилятору все равно?
0
"C with Classes"
1498 / 1296 / 489
Регистрация: 16.08.2014
Сообщений: 5,442
Записей в блоге: 1
19.10.2018, 11:18 18
Цитата Сообщение от Croessmah Посмотреть сообщение
указатель на указатель
нет такого типа данных!
0
Don't worry, be happy
17205 / 10083 / 1945
Регистрация: 27.09.2012
Сообщений: 25,158
Записей в блоге: 1
19.10.2018, 11:20 19
COKPOWEHEU,
Во-первых, такая запись сама по себе воспринимается сложнее.
Во-вторых, такая запись всё равно не дает никаких гарантий.
В-третьих, слабо верится, что разработчику функции нужна эта подсказка, а для пользователя она всё равно недостаточна, нужно лезть в документацию.
В-четвертых, удобство такой подсказки - это как выбор цвета шапки, кому-то нравится, кому-то нет. Лично я из второй категории и считаю такую запись говеной.

Добавлено через 17 секунд
_stanislav, молодец
0
Нарушитель
3063 / 1670 / 578
Регистрация: 23.09.2014
Сообщений: 5,199
19.10.2018, 11:23 20
Цитата Сообщение от Croessmah Посмотреть сообщение
И в чем разница?
если вам нужна разница, то можно и так:
C++
1
void func(Class*& m[], int)
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
19.10.2018, 11:23

Указатели. Важность указателей
Здарова! Я хорошо понимаю (относительно хорошо, конечно), что такое указатели. Я слышал, что...

Указатели. Вычитание указателей
Сам читаю книгу Шилдта. Глава с указателями, написано - &quot;Если складывать указатели нельзя, то...

Инициализация массива указателей на указатели
Всем привет. Есть такой код: char **pchAr = new char*; //в цикле по i pchAr = new char; ...

Указатели. Сравнение двух указателей и их sizeof()
Есть код: int main() { int x = 10; int y = 10; int *xptr = &amp;x; int *yptr = &amp;y;...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.