Форум программистов, компьютерный форум CyberForum.ru

Передача указателей в функции - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 60, средняя оценка - 4.83
_Eldar_
 Аватар для _Eldar_
44 / 29 / 3
Регистрация: 31.10.2009
Сообщений: 200
15.02.2010, 06:57     Передача указателей в функции #1
Привет всем. Вообщем изучаю с\с++ по книге Павловской, дошел до динамических структур данных(списки, стеки, очереди...), Вообщем наткнулся там на пример списка, не могу понять как передаються ьам указатели в функции. А конкретно не понятны передачи указателей в функции add и remove. Объясните пожалйуста подробно, заранее благодарен всем отозвавшимся.
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <windows.h>
#include <conio.h>
#include <iostream>
 
using namespace std;
 
struct Node{
    int d;
    Node *next;
    Node *prev;
};
 
Node * first(int d);
void add(Node **pend, int d);
Node * find(Node * const pbeg, int i);
bool remove(Node **pbeg, Node **pend, int key);
Node * insert(Node * const pbeg, Node **pend, int key, int d);
//-------------------------------------
int main(){
 
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
 
    Node *pbeg = first(1); // Формирование первого элемента списка
    Node *pend = pbeg;     //Список заканчивается, едва начавшись
    // Добавление в конец списка четырех элементов 2, 3, 4 и 5
    for(int i = 2; i < 6; i++) add(&pend, i);
    //Вставка элемента 200 после элемента 2
    insert(pbeg, &pend, 2, 200);
    //удаление элемента 5;
    if(!remove(&pbeg, &pend, 5)) cout << "не найден";
    Node *pv = pbeg;
    while(pv){ // Вывод списка на экран
        cout << pv->d << " ";
        pv = pv->next;
    }   
    
    _getch();
    return 0;
}
//--------------------------------------
//Формирование первого элемента
Node * first(int d){
    Node *pv = new Node;
    pv->d = d; pv->next = 0; pv->prev = 0;
    return pv;
}
//---------------------------------------
//Добавление в конец списка
void add(Node **pend, int d){
    Node *pv = new Node;
    pv->d = d; pv->next = 0; pv->prev = *pend;
    (*pend) ->next = pv;
    *pend = pv;
}
//-----------------------------------------
//Поиск элемента по ключу
Node * find(Node * const pbeg, int d){
    Node *pv = pbeg;
    while(pv){
        if(pv->d == d) break;
        pv = pv->next;
    }
    return pv;
}
//-----------------------------------------
//Поиск элемента по ключу
bool remove(Node **pbeg, Node **pend, int key){
    if(Node *pkey = find(*pbeg, key)){
        if(pkey == *pbeg){
            *pbeg = (*pbeg)->next;
            (*pbeg)->prev = 0;
        }
        else if(pkey == *pend){
            *pend = (*pend)->prev;
            (*pend)->next = 0;
        }
        else{
            (pkey->prev)->next = pkey->next;
            (pkey->next)->prev = pkey->prev;
        }
        delete pkey;
        return true;
    }
    return false;
}
//---------------------------------
//Вставка элемента
Node * insert(Node * const pbeg, Node **pend, int key, int d){
    if(Node *pkey = find(pbeg, key)){
        Node *pv = new Node;
        pv->d = d;
        // 1 - установление связи нового узла с последующим:
        pv->next = pkey->next;
        // 2 - установление связи нгового узла с предыдущим:
        pv->prev = pkey;
        // 3 - установление связи предыдущего узла с новым:
        pkey->next = pv;
        // 4 - установление связи последующего узла с новым:
        if(pkey != *pend)(pv->next)->prev = pv;
        // Обновление указателя на конец списка,
        // если узел вставляется в конец :
        else *pend = pv;
        return pv;
    }
    return 0;
}
Добавлено через 26 минут
т.е. не понятно объявление этих функций, передача в них указателей и обращение к ним в теле функций.

Добавлено через 4 часа 31 минуту
народ, помогите разобраться пожалуйста
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
darkAngel
Технофашист
206 / 187 / 3
Регистрация: 11.03.2009
Сообщений: 829
15.02.2010, 07:53     Передача указателей в функции #2
C++
1
Node * first(int d);
Это означает, что тип, возвращаемого функцией параметра, является указатель на Node.


C++
1
void add(Node **pend, int d)
Параметр **pend означает указатель на указатель. Т.е. переменная, которая содержит в себе адрес ячеек памяти, которые в свою очередь содержат адрес дрйгой ячейки памяти.
C++
1
*pend = pv;
Эта операция означает, что теперь указатель pend указывает на ячейку памяти, в которй содержится указатель pv (который в свою очередь ссылает на другую ячейку памяти)
C++
1
(*pend) ->next = pv;
Здесь скобочки это доступ к указателю, на который ссылается pend. Т.е. после операции присвоения "=" изменяем не сам указатель pend, а изменяем указатель, на который ссылается pend. (а он здесь ссылается на указатель типа Node)

И для того, чтобы вызвать функцию, параметром которой является указатель на указатель (например **pend), на до при вызове функции использовать операцию взятия адреса. ну т.е. add(&uk), где uk это **uk (т.е. также указатель на указателЬ)

Добавлено через 2 минуты
p.s. А вообще у Павловской в книжке есть и про указатели и про функции с параметрами типа указатель.
_Eldar_
 Аватар для _Eldar_
44 / 29 / 3
Регистрация: 31.10.2009
Сообщений: 200
15.02.2010, 08:03  [ТС]     Передача указателей в функции #3
есть, но передача указателя на указатель в функцию встретилась впервые, а если я передаю указатель на указатель который указывает еще на один указатель, напимер function(***param), как мне вызывать ее? function(&parametr)? Операция "&" возвращает адрес самого указателя, т.е. в данном случае адрес указателя на указатель, который указывает на другой указатель.

Добавлено через 2 минуты
и еще в заголовке функции
C++
1
void add(Node **pend, int d)
параметр - указатель на указатель, а в теле функции обращение к нему(параметру) как простому указателю *pend на структуру

Добавлено через 3 минуты
и почему в функции
C++
1
bool remove(Node **pbeg, Node **pend, int key);
pbeg - передается как указатель на указатель, ведь он является просто указателем на первую структуру в списке, а не указателем на указатель
accept
4837 / 3236 / 165
Регистрация: 10.12.2008
Сообщений: 10,682
15.02.2010, 10:10     Передача указателей в функции #4
C
1
void func(int n);
такая функция во время своего вызова создаст переменную n и уничтожит её после своего вызова

C
1
void func(int *n);
такая функция во время своего вызова создаст переменную n и уничтожит её после своего вызова

пока переменная существует внутри функции, мы можем читать из неё данные и помещать в неё данные

C
1
void func(int *n);
C
1
    *n = 3;
операция разыменования читает содержимое переменной n
интерпретирует это содержимое как адрес
заменяет выражение *n на область памяти, имеющую этот адрес
записывает в эту область 3

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

C++
1
bool remove(Node **pbeg, Node **pend, int key);
такое применяют, когда хотят изменить содержимое переменных
мы убираем первые звёздочки
C++
1
bool remove(Node *pbeg, Node *pend, int key);
что мы видим
что в функцию будут переданы переменные pbeg и pend, которые обе являются указателями, и key, которая является целым числом
но pbeg и pend, в отличие от key, будут меняться функцией remove

что значит изменить указатель
C
1
2
3
4
5
6
7
8
9
10
    int a, b, *p;
 
    a = 1;
    b = 2;
 
    p = &a; /* записали в переменную p указатель на переменную a */
 
    p = &b; /* записали в переменную p адрес переменной b */
 
    p = NULL; /* записали в переменную p нулевой указатель (void *) 0 */
сперва указатель содержал мусор
потом он стал хранить адрес переменной a
потом он стал хранить адрес переменной b
потом он стал хранить адрес равный нулю данных пустого типа (недоступных данных)

C
1
2
3
4
5
6
    int a; 
    int *b;
    int **c;
    
    b = &a;
    c = &b;
как узнать адрес данных какого типа хранит указатель
мы просто убираем одну здвёздочку

C
1
2
    int b; /* было *b, а стало b */
    int *c; /* было **c, а стало *c */
получилось, что b хранит адрес переменной типа int
а c хранит адрес переменной типа int *
возвращаем звёздочку на место

C
1
2
3
4
5
6
7
8
9
10
    int a; 
    int *b;
    int **c;
 
    a = 1;    
    b = &a;
    c = &b;
    b = *c; /* это равносильно b = b */
    a = **c; /* это равносильно a = a */
    **c = 2; /* это равносильно a = 2 и *b = 2 */
подробно последнюю
C
1
    **c = 2;
разыменовали содержимое переменной c
содержимое переменной c - это адрес переменной b
разыменовав адрес переменной b, мы получили содержимое переменной b
разыменовали содержимое переменной b
содержимое переменной b - это адрес переменной a
разыменовав адрес переменной a, мы получили содержимое переменной a
так как содержимое переменной a стоит в левой части присваивания, в него записывается значение 2
новое содержимое переменной a равно двум

C++
1
2
3
4
        if(pkey == *pbeg){
            *pbeg = (*pbeg)->next; // вот изменение указателя pbeg
            (*pbeg)->prev = 0;
        }
там где *pbeg =
разыменовали содержимое pbeg (remove)
содержимое pbeg (remove) - это адрес pbeg (main)
разыменовав содержимое pbeg (remove), получили содержимое pbeg (main)
так как содержимое переменной pbeg (main) стоит в левой части присваивания, в него записывается значение (*pbeg)->next, это pbeg->next (main)
новое содержимое переменной pbeg (main) равно адресу, который хранится в pbeg->next (main)
голова списка переставляется на следующий элемент
_Eldar_
 Аватар для _Eldar_
44 / 29 / 3
Регистрация: 31.10.2009
Сообщений: 200
15.02.2010, 10:14  [ТС]     Передача указателей в функции #5
ОГРОМЕННОЕ СПАСИБО ЗА ОТВЕТ) буду разбираться)
accept
4837 / 3236 / 165
Регистрация: 10.12.2008
Сообщений: 10,682
15.02.2010, 10:25     Передача указателей в функции #6
новое содержимое переменной pbeg (main) равно адресу, который хранился в pbeg->next (main)
голова списка переставилась на следующий элемент

Добавлено через 22 секунды
поправил последние две строчки для однозначности
_Eldar_
 Аватар для _Eldar_
44 / 29 / 3
Регистрация: 31.10.2009
Сообщений: 200
19.02.2010, 04:32  [ТС]     Передача указателей в функции #7
accept, Возник еще такой вопрос.Есть функция
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int write_dbase(char* filename, Order* pv){
 
    ofstream fout(filename);
    if(!fout){cout << "\nОшибка открытия файла"; return 1;}
 
    while(pv){
        fout << pv->name  << endl;
        fout << pv->model << endl;
        fout << pv->work  << endl;      
        fout << pv->time << ' ' << pv->price << endl;
        pv = pv->next;
    }
    return 0;
}
где pv - это указатель на структуру. Почему в теле функции обращение к нему идет не через операцию разыменовывания *pv?

Добавлено через 8 минут
Пример из практикума Павловской

Добавлено через 6 минут
Есть ли вообще где-нибудь список правил передачи указателей в функции и обращения к ним в функциях (ПОДРОБНЫЙ, чтоб рассматривались всевозможные варианты)?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
19.02.2010, 05:44     Передача указателей в функции
Еще ссылки по теме:

Создать специфицированный шаблон функции, принимающей массив указателей на char и количество самих указателей C++
C++ Передача указателей в методы по ссылке
C++ Передача массива указателей в функцию для выделения памяти

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

Или воспользуйтесь поиском по форуму:
accept
4837 / 3236 / 165
Регистрация: 10.12.2008
Сообщений: 10,682
19.02.2010, 05:44     Передача указателей в функции #8
операция разыменования скрыта в операции ->
pv->name подобна (*pv).name
различия

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <stdlib.h>
 
int main(void) /* C89 ANSI */
{
    struct x {
        struct x *p;
        int n;
    } s, a, b, c;
    
    c.n = 5;
    
    s.p = &a;
    a.p = &b;
    b.p = &c;
    
    printf("%d" "\n", s.p->p->p->n);
    
    printf("%d" "\n", (*(*(*s.p).p).p).n);
 
    exit(EXIT_SUCCESS);
}


Цитата Сообщение от _Eldar_
список правил передачи указателей в функции и обращения к ним в функциях
вообще ничем не отличаются указатели в функциях и указатели сами по себе
указатель - это обычная переменная

C
1
int write_dbase(char* filename, Order* pv)
при вызове функции write_dbase создаются две локальные переменные
filename и pv
они уничтожаются после завершения функции и их содержимое тоже
содержимое каждой является адресом

C
1
    write_dbase(f, p);
в f и p находятся какие-то адресы
вызов write_dbase() создаёт filename и pv
в filename он копирует содержимое переменной f
в pv он копирует содержимое переменной p

понятно, что адрес нельзя удалить
его можно записать в нескольких местах
это будут записи адреса, его копии
и вот копии можно удалить
Yandex
Объявления
19.02.2010, 05:44     Передача указателей в функции
Ответ Создать тему
Опции темы

Текущее время: 21:07. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru