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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
gru74ik
Модератор
Эксперт CЭксперт С++
4178 / 1806 / 197
Регистрация: 20.02.2013
Сообщений: 4,943
Записей в блоге: 21
#1

Указатели на функции (Прата) - не пойму, как это работает - C++

16.07.2014, 17:42. Просмотров 1092. Ответов 28
Метки нет (Все метки)

Стивен Прата "Язык программирования C++. Лекции и упражнения"
7 глава, стр. 355, листинг 7.18. fun_ptr.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
// fun_ptr.cpp -- pointers to functions
#include <iostream>
double betsy(int);
double pam(int);
 
// second argument is pointer to a type double function that
// takes a type int argument
void estimate(int lines, double (*pf)(int));
 
int main()
{
    using namespace std;
    int code;
 
    cout << "How many lines of code do you need? ";
    cin >> code;
    cout << "Here's Betsy's estimate:\n";
    estimate(code, betsy);
    cout << "Here's Pam's estimate:\n";
    estimate(code, pam);
    // cin.get();
    // cin.get();
    return 0;
}
 
double betsy(int lns)
{
    return 0.05 * lns;
}
 
double pam(int lns)
{
    return 0.03 * lns + 0.0004 * lns * lns;
}
 
void estimate(int lines, double (*pf)(int))
{
    using namespace std;
    cout << lines << " lines will take ";
    cout << (*pf)(lines) << " hour(s)\n";
}
Вопрос. Я как бы понял, что в прототипе функции можно написать только типы
аргументов, опустив имена; либо написать те самые имена, которые будут в
реализации функции; либо вовсе написать любые удобные имена, которые будут
служить своеобразной подсказкой - это не важно, компилятор всё равно эти имена
пропустит.
В прототипах функций betsy() и pam() указаны только типы аргументов, это я
понял. В прототипе функции estimate() указаны имена-подсказки lines и pf
соответственно. Несмотря на то, что нигде потом не будет объявлена переменная
int lines и указатель pf, компилятор понимает, что первым аргументом функции
estimate() должно быть целое число, либо целочисленная переменная (в нашем
случае - переменная int code), а вторым аргументом указатель на функцию (в нашем
случае это betsy и pam, соответственно). Понимает почему? Потому что при вызове
функции estimate() на месте int lines стоит int code, а на месте double (*pf)(int) стоит
betsy (или во втором вызове - pam).
Но я хоть убей не могу понять, каким волшебным образом компилятор понимает,
что переменная int lns - это та же самая int code. Откуда он берёт это знание?
С чего он вообще решил, что надо подставить вместо int lns переменную int code?
0
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
16.07.2014, 17:42
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Указатели на функции (Прата) - не пойму, как это работает (C++):

Не пойму, куда и как вставить функции и указатели - C++
Дан массив из N чисел. Найти наибольший элемент массива и поменять его местами с наименьшим элементом. #include&lt;iostream.h&gt; #define N...

Прата и умные указатели - C++
Читаю Прата С. - Язык программирования С++. Лекции и упражнения - 2011, стр. 886: Пишу, компилирую - получаю ошибки: Кто не прав...

Не пойму как работает char - C++
Выдает не символ, а сивол и число!!Это я уже пробую явное приведение. Кто поопытней, поясните!! #include&lt;iostream&gt; #include&lt;conio.h&gt; ...

Не пойму как работает класс - C++
Hi all Не пойму как работает пример #include &lt;stdafx.h&gt; #include &lt;conio.h&gt; using namespace std; class String { public: char*...

Динамические двумерные массивы через указатели. Как это происходит? - C++
Вот типичная идентификация двумерного массива (NxM): int** mass = new int*; for(i=0; i&lt;N; i++) mass = new int; Помогите...

Указатели и сссылки. Надо ли обнулять? когда и как это делать? - C++
насчет ссылок вроде все ясно. обнулять их нет смысла на сколько я понимаю. А вот насчет указателей не все так просто. В книгах часто,...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
jurok_85
241 / 224 / 77
Регистрация: 21.02.2013
Сообщений: 519
Завершенные тесты: 1
16.07.2014, 17:55 #2
C++
1
2
3
4
estimate(code, betsy);
...
...
void estimate(int lines, double (*pf)(int))
первый аргумент функции, получается lines равно code
0
gru74ik
Модератор
Эксперт CЭксперт С++
4178 / 1806 / 197
Регистрация: 20.02.2013
Сообщений: 4,943
Записей в блоге: 21
16.07.2014, 18:46  [ТС] #3
Всё, дошло.
В 18-й строке компилятору дали понять, что вместо int lines надо подставить int code.
А в реализации estimate() в 40-й строке кода становится понятно, что переменная lines - это та же lns.
Что-то типа псевдоним псевдонима. Только нафига было огород городить? Почему было не написать так:
C++
1
2
3
4
5
6
7
8
9
double betsy(int lines)
{
    return 0.05 * lines;
}
 
double pam(int lines)
{
    return 0.03 * lines + 0.0004 * lines * lines;
}
?

Добавлено через 27 минут
Цитата Сообщение от jurok_85 Посмотреть сообщение
первый аргумент функции, получается lines равно code
А из первого сообщения топика разве было не понятно, что это я и сам понял?

Вопрос же чётко был поставлен:
Цитата Сообщение от gru74ik Посмотреть сообщение
Но я хоть убей не могу понять, каким волшебным образом компилятор понимает,
что переменная int lns - это та же самая int code. Откуда он берёт это знание?
Теперь вопрос в следующем:
Цитата Сообщение от gru74ik Посмотреть сообщение
нафига было огород городить?
Зачем Прата наплодил сущностей в этом примере?

Добавлено через 19 минут
Цитата Сообщение от gru74ik Посмотреть сообщение
Зачем Прата наплодил сущностей в этом примере?
Перечитал главу ещё раз. Дошло почему. Предполагается, что estimate() писал один
программист, а pam() и betsy() другой (или другие). Поэтому и в estimate() переменную
обозвали lines, а в pam() и betsy() - lns:
Цитата Сообщение от Стивен Прата
Проясним этот процесс на примере. Предположим, что требуется спроектировать
функцию estimate (), которая оценивает затраты времени, необходимого для
написания заданного количества строк кода, и вы хотите, чтобы этой функцией
пользовались разные программисты. Часть кода estimate () будет одинакова для
всех пользователей, но эта функция позволит каждому программисту применить
собственный алгоритм оценки затрат времени.
0
DrOffset
7138 / 4279 / 964
Регистрация: 30.01.2014
Сообщений: 7,073
16.07.2014, 19:11 #4
Цитата Сообщение от gru74ik Посмотреть сообщение
Но я хоть убей не могу понять, каким волшебным образом компилятор понимает,
что переменная int lns - это та же самая int code
Это не та же самая переменная.
Компилятор ничего не "подставляет". Он генерирует машинный код, который, условно говоря, копирует содержимое ячейки памяти обозначенной как code в ячейку памяти обозначенную как lines. Естественно в машинном коде никаких имен нет, есть только адреса. И это мы еще не касаемся такой темы как оптимизация.

Указатели на функцию здесь исключительно в качестве синтетического примера. Искать глубинный смысл этого кода довольно затруднительно, учитывая, что смысл только в демонстрации (механизма).
1
gru74ik
Модератор
Эксперт CЭксперт С++
4178 / 1806 / 197
Регистрация: 20.02.2013
Сообщений: 4,943
Записей в блоге: 21
17.07.2014, 13:21  [ТС] #5
Цитата Сообщение от DrOffset Посмотреть сообщение
Компилятор ничего не "подставляет". Он генерирует машинный код, который, условно говоря, копирует содержимое ячейки памяти обозначенной как code в ячейку памяти обозначенную как lines.
Ясно. Благодарю!
0
gru74ik
Модератор
Эксперт CЭксперт С++
4178 / 1806 / 197
Регистрация: 20.02.2013
Сообщений: 4,943
Записей в блоге: 21
19.07.2014, 13:59  [ТС] #6
Поиздевался над кодом, чтобы немного уяснить для себя, как всё это работает:
Кликните здесь для просмотра всего текста

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
// fun_ptr.cpp -- pointers to functions
#include <iostream>
double betsy(int);
double pam(int);
 
// Второй аргумент — указатель на функцию double,
// которая принимает аргумент типа int
void estimate(int lines, double (*pf)(int));
 
int main()
{
    using namespace std;
    int code;
 
    cout << "How many lines of code do you need? ";
    cin >> code;
 
    cout << "Here's Betsy's estimate:\n";
    estimate(code, betsy);
    cout << "Here's Pam's estimate:\n";
    estimate(code, pam);
 
    cout << "\n\tAddress of variable int code in"
    " function estimate() is\t" << &code << endl;
    cout << "\tValue of variable int code in"
    " function estimate() is\t" << code << endl;
    cout << endl;
 
    // cin.get();
    // cin.get();
    return 0;
}
 
double betsy(int lns)
{
    std::cout << "\n\tAddress of variable int lns in"
    " function betsy() is\t" << &lns << std::endl;
    std::cout << "\tValue of variable int lns in"
    " function betsy() is\t" << lns << std::endl;
    std::cout << std::endl;
 
    return 0.05 * lns;
}
 
double pam(int lns)
{
    std::cout << "\n\tAddress of variable int lns in"
    " function pam() is\t" << &lns << std::endl;
    std::cout << "\tValue of variable int lns in"
    " function pam() is\t" << lns << std::endl;
    std::cout << std::endl;
 
    return 0.03 * lns + 0.0004 * lns * lns;
}
 
void estimate(int lines, double (*pf)(int))
{
    using namespace std;
    cout << lines << " lines will take ";
    cout << (*pf)(lines) << " hour(s)\n";
 
    cout << "\tAddress of variable int lines in"
    " function estimate() is\t" << &lines << endl;
    cout << "\tValue of variable int lines in"
    " function estimate() is\t" << lines << endl;
    cout << endl;
}


Вот интересно, каким образом int lns в функции betsy() и int lns в функции pam() имеют один и тот же адрес? Я так понимаю, это должны быть разные переменные с разными адресами, ведь они локальные (инкапсулированы внутри функций)?
0
Миниатюры
Указатели на функции (Прата) - не пойму, как это работает  
castaway
Эксперт С++
4884 / 3020 / 370
Регистрация: 10.11.2010
Сообщений: 11,078
Записей в блоге: 10
Завершенные тесты: 1
19.07.2014, 14:05 #7
Они локальные, и находятся в стеке, поэтому вполне очевидно что при вызове этих функций указатель стека будет одинаковым.
0
gru74ik
Модератор
Эксперт CЭксперт С++
4178 / 1806 / 197
Регистрация: 20.02.2013
Сообщений: 4,943
Записей в блоге: 21
19.07.2014, 14:09  [ТС] #8
Цитата Сообщение от castaway Посмотреть сообщение
Они локальные, и находятся в стеке
Это понял.
Цитата Сообщение от castaway Посмотреть сообщение
очевидно что при вызове этих функций указатель стека будет одинаковым
Это не понял. Какой указатель?
0
gru74ik
Модератор
Эксперт CЭксперт С++
4178 / 1806 / 197
Регистрация: 20.02.2013
Сообщений: 4,943
Записей в блоге: 21
19.07.2014, 14:15  [ТС] #9
Блин, разные функции, разные переменные. Как у них может быть один и тот же адрес?
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
// fun_ptr.cpp -- pointers to functions
#include <iostream>
double betsy(int);
double pam(int);
 
// Второй аргумент — указатель на функцию double,
// которая принимает аргумент типа int
void estimate(int lines, double (*pf)(int));
 
int main()
{
    using namespace std;
    int code;
 
    cout << "How many lines of code do you need? ";
    cin >> code;
 
    cout << "Here's Betsy's estimate:\n";
    estimate(code, betsy);
    cout << "Here's Pam's estimate:\n";
    estimate(code, pam);
 
    cout << "\n\tAddress of variable int code in"
    " function estimate() is\t" << &code << endl;
    cout << "\tValue of variable int code in"
    " function estimate() is\t" << code << endl;
    cout << endl;
 
    // cin.get();
    // cin.get();
    return 0;
}
 
double betsy(int bet_lns)
{
    std::cout << "\n\tAddress of variable int bet_lns in"
    " function betsy() is\t" << &bet_lns << std::endl;
    std::cout << "\tValue of variable int bet_lns in"
    " function betsy() is\t" << bet_lns << std::endl;
    std::cout << std::endl;
 
    return 0.05 * bet_lns;
}
 
double pam(int pam_lns)
{
    std::cout << "\n\tAddress of variable int pam_lns in"
    " function pam() is\t" << &pam_lns << std::endl;
    std::cout << "\tValue of variable int pam_lns in"
    " function pam() is\t" << pam_lns << std::endl;
    std::cout << std::endl;
 
    return 0.03 * pam_lns + 0.0004 * pam_lns * pam_lns;
}
 
void estimate(int lines, double (*pf)(int))
{
    using namespace std;
    cout << lines << " lines will take ";
    cout << (*pf)(lines) << " hour(s)\n";
 
    cout << "\tAddress of variable int lines in"
    " function estimate() is\t" << &lines << endl;
    cout << "\tValue of variable int lines in"
    " function estimate() is\t" << lines << endl;
    cout << endl;
}
0
Миниатюры
Указатели на функции (Прата) - не пойму, как это работает  
castaway
Эксперт С++
4884 / 3020 / 370
Регистрация: 10.11.2010
Сообщений: 11,078
Записей в блоге: 10
Завершенные тесты: 1
19.07.2014, 14:16 #10
В процессорах есть регистр SP (stack pointer), в котором хранится адрес вершины стека.
Хотя бы небольшое знание языка Assembler поможет лучше разобраться в языке C++.
2
gru74ik
Модератор
Эксперт CЭксперт С++
4178 / 1806 / 197
Регистрация: 20.02.2013
Сообщений: 4,943
Записей в блоге: 21
19.07.2014, 14:19  [ТС] #11
Цитата Сообщение от castaway Посмотреть сообщение
Хотя бы небольшое знание языка Assembler поможет лучше разобраться в языке C++.
Ладно. Пока приму как данность. Сейчас ещё и в ассемблер вникать не потяну.
0
castaway
Эксперт С++
4884 / 3020 / 370
Регистрация: 10.11.2010
Сообщений: 11,078
Записей в блоге: 10
Завершенные тесты: 1
19.07.2014, 14:24 #12
Я бы попробовал объяснить, но мне с телефона это будет очень неудобно.
1
gru74ik
Модератор
Эксперт CЭксперт С++
4178 / 1806 / 197
Регистрация: 20.02.2013
Сообщений: 4,943
Записей в блоге: 21
19.07.2014, 14:32  [ТС] #13
Цитата Сообщение от castaway Посмотреть сообщение
Я бы попробовал объяснить
Благодарю за отзывчивость!

Цитата Сообщение от castaway Посмотреть сообщение
но мне с телефона это будет очень неудобно.
Не стоит если не слишком удобно - мне не горит. Потом как-нибудь. Или сам разберусь чуть позже.
0
nonedark2008
908 / 647 / 134
Регистрация: 28.07.2012
Сообщений: 1,760
19.07.2014, 15:36 #14
Цитата Сообщение от castaway Посмотреть сообщение
В процессорах есть регистр SP (stack pointer), в котором хранится адрес вершины стека.
Когда вызывается функция, то ее аргументы помещаются в вершину стека, после отработки функции они из стека убираются. Следовательно, вполне очевидно, что при следующем вызовн функции ее аргументы будут помещены в стеке на то же место, где были предыдущие.
2
Tulosba
:)
Эксперт С++
4395 / 3238 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
19.07.2014, 15:41 #15

Не по теме:

Цитата Сообщение от castaway Посмотреть сообщение
Я бы попробовал объяснить, но мне с телефона это будет очень неудобно.
С телефона проще оставить голосовое сообщение


По теме: будет полезно ознакомиться с соглашениями о вызове.
2
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
19.07.2014, 15:41
Привет! Вот еще темы с ответами:

Как это работает? Я хочу спросить как работает C++ и где можно про него почитать - C++
Привет, котоны. Заранее благодарю. Это будет моих общих вопросов нить, т.к. создавать целую ветку для каждого нецелесообразно. Я хочу...

Прата С. С++. Посчитать количество вызовов функции - C++
Всем привет! Закончил раздел про встроенные функции, шаблоны, полиморфизм и ссылочные переменные. Там в конце такое задание: Напиши...

Не пойму что это за ошибки - C++
Обьясните что это за ошибки и что с ними делать 1) invalid initialization of reference of type 'TPQueue* &amp;' from expression of type...

не пойму что это за ошибка( - C++
помогите пожалуйста! я нашла программу подходящюю мне по заданию, добавила в нее необходимые библиотеки, и при компиляции она выдает ошибку...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
19.07.2014, 15:41
Ответ Создать тему
Опции темы

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