Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > в чем разница


Автор: bend0r 14.9.2005, 13:08
в учебнике Павловской код линейного списка такой
Код

struct Node
{
   int d;  
   Node *next; 
   Node *prev; 
};

//-----------------------------------------------

Node *first(int d);
void add(Node **pend, int d);
Node *find(Node *const pbed, int i);
bool remove(Node **pbeg, Node **pend, int key, int d);
Node *insert(Node *const pbed, Node **pend, int key, int d);

//Формирования первого элемента

Node *first(int d)
{
   Node *pv=new Node;
   pv->=d;
   pv->next=0;
   pv->prev=0;
}


//-------------------------------------------------
//Добавление в конец списка

void add(Node **pend, int d)
{
   Node *pv=new Node;
   pv->d;
   pv->next=0,
   pv->prev=*pend;
   (*pend)->next=pv;
   *pend=pv;
}

int main()
{
Node *pbeg=first(1);
Node *pend=pbeg;
for(int i=2; i<6; i++) add(&pend,i);
....

}


если заменить на
Код

void add(Node *pend, int d);


Код

void add(Node *pend, int d)
{
   Node *pv=new Node;
   pv->d;
   pv->next=0,
   pv->prev=pend;
   pend->next=pv;
   pend=pv;
}


Код

for(int i=2; i<6; i++) add(pend,i);


в чем будет разница и вообще для чего надо было использовать указатель на указатель?

Автор: Дрон 14.9.2005, 13:10
Цитата(bend0r @ 14.9.2005, 14:08)
в учебнике Павловской код линейного списка такой

Я рад за неё.

А где вопрос? smile

Автор: bend0r 14.9.2005, 13:14
во терь есть вопрос, не туда нажал smile

Автор: Дрон 14.9.2005, 13:26
Ок smile

Разница есть.
В последней строчке функции add() мы присаеваем новое значение для pend. Если сделать так, как ты написал во втором варианте, то при вызове функции будет создана копия pend, все изменения которой после выхода из функции будут потеряны.

Как я понимаю, это учебник по Си, а не С++? smile

Автор: srd 14.9.2005, 13:31
Судя по оператору new - это всё-таки Си++. Какой ужас smile Эта мадам Павловская детей плохому научит...

Автор: Дрон 14.9.2005, 13:37
Цитата(srd @ 14.9.2005, 14:31)
Судя по оператору new - это всё-таки Си++. Какой ужас smile Эта мадам Павловская детей плохому научит...

Опа... Тогда, конечно, ужас... smile

Автор: bend0r 14.9.2005, 14:12
всеравно не понятно smile

В моем варианте в add() передается указатель, делается копия его, сама функцияя работает с тем на что он указывает, при выходе из функции потерены будут если тока изменения адреса указателя. так ведь оно или не так? smile

вот щас тестил помоему тоже самое:
Код

void f(int *);
int main()
{
   int *p;
   int a=10;
   p=&a;
   cout<<"Do fun "<<*p<<endl;
   f(p);
   cout<<"Posle "<<*p<<endl;
   cout<<"a= "<<a;
   int aa;
   cin>>a;
}

void f(int *p)
{
   *p=*p+5;
   cout<<"V fun "<<*p<<endl;
}



результат:
Do fun 10
V fun 15
Posle 15
a= 15

p/s/ учебник по Си/Си++. учебник вообще зло не кому не советую если узучать с 0 и это первый язык который изучаете. мне его мой препод посоветовал smile

Автор: Дрон 14.9.2005, 14:29
bend0r
Блин...
А ты ведь прав. Там никакой разницы.

Автор: Doc_d0s 14.9.2005, 17:11
Просто мы когда используем *pend а не **pend меняем указатель лишь в теле ф-ии, но не глобально
ИМХО такой подход реален если пенд у тя будет глобальным и не будет параметром ф-ии

Автор: bend0r 14.9.2005, 19:18
Цитата(Doc_d0s @ 14.9.2005, 17:11)
Просто мы когда используем *pend а не **pend меняем указатель лишь в теле ф-ии, но не глобально
ИМХО такой подход реален если пенд у тя будет глобальным и не будет параметром ф-ии

не совсем понятно.

есть вообще какое нибуть практическое применение у указателю на указатель(кроме динамической матрицы)?
небольшой пример не помешалбы smile

Автор: Mayk 14.9.2005, 19:36
Цитата(bend0r @ 14.9.2005, 23:18)
небольшой пример не помешалбы

Ты привёл его сам в первом посте smile

Обрати внимание на
*pend=pv;

Этой командой изменяется pend из ф-ции main:
add(&pend,i);

В твоём втором примере(когда передаётся просто указатель -- void add(Node *pend, int d);) указатель копируется, и ф-ция add работает с копией указателя. Указатель из ф-ции main НЕ изменяется функцией add из второго примера.

А вот в случае, когда передается указатель на указатель на pend, то ф-ция add может заменить значение указателя в функции main.

Чтоб стало наглядно понятно замени в первом примере основной цикл на
Код

for(int i=2; i<6; i++) {
     printf("pend=%p\n",pend);
     add(&pend,i); 
}

а во втором на
Код

for(int i=2; i<6; i++) {
     printf("pend=%p\n",pend);
     add(pend,i);
}

Ф-ция printf("pend=%p\n",pend); выведет значение указателя в удобо читаемом виде. Во втором примере оно не будет изменяться.

Автор: BreakPointMAN 14.9.2005, 21:26
Когда-то я тоже читал Павловскую... и сделал на форзаце сей книги (да, есть у меня вредная привычка читать книгу с карандашом...) %)) такие пометки:
Цитата

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

Для того, чтобы передать параметр по адресу и производить внутри функции действия непосредственно с ним, нужно использовать передачу по ссылке или через указатель. Тогда в вызванной функции не будет создаваться отдельная копия параметра, а будет использован непосредственно переданный объект. Если мы используем передачу параметра по ссылке, мы должны в описании заголовка функции добавить значок "&" перед именем параметра, но после его типа, например:
Код

void f(int &k)

В теле функции мы можем обращаться к параметру по имени, т.е.:
Код

cout <<k<<endl;

Если мы используем передачу параметра через указатель, вместо "&" мы пишем "*", и при обращении к параметру внутри функции мы должны предварять его "*", потому что это указатель, а значение указателя - адрес объекта, а не его значение; получение значения объекта через указатель на него называется разыменованием, а "*" - операцией разыменования. Пример:
Код

void f(int *j)
   {
    (*j)++;
   }


Но все сказанное выше относится не только к простым стандартным типам, но и к указателям. Что есть указатель? Указатель - это переменная, значением которой является адрес какого-либо объекта в памяти. Если мы в качестве фактического параметра при передаче в функцию используем непосредственно имя указателя, у нас он будет передан по значению, а не по адресу. Внутри функции будет создана копия этого указателя, т.е. указатель того же типа и адресующий тот же объект, но с совершенно другим адресом. Это позволит нам обращаться к объекту, который адресовал передаваемый указатель, и даже изменять этот объект, но мы никогда не сможем изменить значение "настоящего" указателя, заставить адресовать его какой-то другой объект. И все по той же причине, что мы работаем с копией "настоящего" указателя, которая имеет другой адрес в памяти, и всего лишь была инициализирована значением "настоящего" указателя. Внутренний, локальный, указатель мы сможем заставить адресовать и другой объект, но на внешнем это никак не отразится.

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


за точность написанного не ручаюсь, ибо был молодой и зелёный... %)) но вроде так... ))

Автор: bend0r 14.9.2005, 22:43
всем спасиба разобрался.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)