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

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

Войти
Регистрация
Восстановить пароль
 
 
gru74ik
Модератор
Эксперт CЭксперт С++
4196 / 1844 / 198
Регистрация: 20.02.2013
Сообщений: 4,990
Записей в блоге: 22
#1

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

16.07.2014, 17:42. Просмотров 1118. Ответов 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++
насчет ссылок вроде все ясно. обнулять их нет смысла на сколько я понимаю. А вот насчет указателей не все так просто. В книгах часто,...

28
castaway
Эксперт С++
4888 / 3023 / 370
Регистрация: 10.11.2010
Сообщений: 11,080
Записей в блоге: 10
Завершенные тесты: 1
19.07.2014, 16:54 #16
Tulosba, да, некоторые соглошения о вызовах подразумевают использование регистров как средство передачи нескольких первых параметров. Но все известные мне компиляторы по-умолчанию используют соглошение о вызове с параметрами в стеке.
1
gru74ik
Модератор
Эксперт CЭксперт С++
4196 / 1844 / 198
Регистрация: 20.02.2013
Сообщений: 4,990
Записей в блоге: 22
19.07.2014, 17:27  [ТС] #17
Цитата Сообщение от castaway Посмотреть сообщение
Но все известные мне компиляторы по-умолчанию используют соглошение о вызове с параметрами в стеке.
The codeblocks-13.12mingw-setup-TDM-GCC-481.exe file includes the TDM-GCC compiler, version 4.8.1, 32 bit.
Этот тоже?
0
Psilon
Master of Orion
Эксперт .NET
5908 / 4805 / 634
Регистрация: 10.07.2011
Сообщений: 14,407
Записей в блоге: 5
Завершенные тесты: 4
19.07.2014, 19:57 #18
Ребят, скажите, а есть ли разница между
C++
1
(*pf)(lines)
и
C++
1
pf(lines)
или он автоматически разыменовывает, и это просто синтаксический сахар, чтобы не писать лишних скобочек (привет, Лисп)?

Всегда писал по второму варианту, сейчас увидел первый, удивился
0
zhvan
Универсальный программист
41 / 33 / 4
Регистрация: 21.12.2013
Сообщений: 374
Записей в блоге: 1
19.07.2014, 20:02 #19
Цитата Сообщение от gru74ik Посмотреть сообщение
что переменная int lns - это та же самая int code. Откуда он берёт это знание?
С чего он вообще решил, что надо подставить вместо int lns переменную int code?
и все же разница между переменными есть, code в функции main(),
а lns в betsy и pam и доступна только в них
0
gru74ik
Модератор
Эксперт CЭксперт С++
4196 / 1844 / 198
Регистрация: 20.02.2013
Сообщений: 4,990
Записей в блоге: 22
19.07.2014, 21:02  [ТС] #20
Цитата Сообщение от Psilon Посмотреть сообщение
Всегда писал по второму варианту, сейчас увидел первый, удивился
Как-то так:
Цитата Сообщение от Стивен Прата
Язык программирования С++. Лекции и упражнения (2012, 6-е издание), глава 7, стр. 355:

История против логики
О, великий синтаксис! Как pf и (*pf) могут быть эквивалентными? Сторонники одной шко-
лы утверждают, что поскольку pf — указатель на функцию, то *pf — функция, поэтому вы
должны использовать для ее вызова (*pf) (). Сторонники другой школы придерживаются
мнения, что поскольку имя функции является указателем на эту функцию, то и любой указа-
тель на функцию должен вести себя как имя функции; отсюда вызов функции через указа-
тель следует записывать как pf (). Язык C++ придерживается компромиссной точки зрения
о том, что обе формы корректны, или, по крайней мере, допустимы, даже несмотря на то,
что они логически несовместимы. Прежде чем вы отвергнете компромисс и выберете для
себя одну форму, вспомните, что допущение несогласованных и логически несовместимых
представлений вполне присуще человеческому мышлению.
Добавлено через 4 минуты
Цитата Сообщение от zhvan Посмотреть сообщение
и все же разница между переменными есть, code в функции main(),
а lns в betsy и pam и доступна только в них
Это понятно (адреса переменных видны же на прикреплённом скриншоте).
Не понятно почему переменная в betsy() и переменная в pam() - это одна и та же переменная? Функции разные, имена переменных разные, а адрес у обеих один и тот же!
1
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
19.07.2014, 22:55 #21
Цитата Сообщение от gru74ik Посмотреть сообщение
Функции разные, имена переменных разные, а адрес у обеих один и тот же!
Точнее чем сказано здесь, вряд ли можно ответить. Я думаю все со мной согласятся, что этот ответ лучший, и тебе нужно просто вникнуть в него.
1
Psilon
Master of Orion
Эксперт .NET
5908 / 4805 / 634
Регистрация: 10.07.2011
Сообщений: 14,407
Записей в блоге: 5
Завершенные тесты: 4
20.07.2014, 03:26 #22
Цитата Сообщение от gru74ik Посмотреть сообщение
Не понятно почему переменная в betsy() и переменная в pam() - это одна и та же переменная? Функции разные, имена переменных разные, а адрес у обеих один и тот же!
почему одна и та же? Можешь разными назвать, это ничего не поменяет:
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
// fun_ptr.cpp -- pointers to functions
#include <iostream>
double betsy(int);
double pam(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);
    return 0;
}
 
double betsy(int x)
{
    return 0.05 * x;
}
 
double pam(int y)
{
    return 0.03 * y + 0.0004 * y * y;
}
 
void estimate(int lines, double(*pf)(int))
{
    using namespace std;
    cout << lines << " lines will take ";
    cout << pf(lines) << " hour(s)\n";
}
можешь даже функции разного типа сделать, все равно работать будет:
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
// fun_ptr.cpp -- pointers to functions
#include <iostream>
double betsy(int);
double pam(double);
 
template <typename FuncPtr>
void estimate(int lines, FuncPtr);
 
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);
    return 0;
}
 
double betsy(int x)
{
    return 0.05 * x;
}
 
double pam(double y)
{
    return 0.03 * y + 0.0004 * y * y;
}
 
template <typename FuncPtr>
void estimate(int lines, FuncPtr pf)
{
    using namespace std;
    cout << lines << " lines will take ";
    cout << pf(lines) << " hour(s)\n";
}
0
gru74ik
Модератор
Эксперт CЭксперт С++
4196 / 1844 / 198
Регистрация: 20.02.2013
Сообщений: 4,990
Записей в блоге: 22
20.07.2014, 13:22  [ТС] #23
Цитата Сообщение от Psilon Посмотреть сообщение
почему одна и та же?
То есть один и тот же адрес - просто дело случая? А переменные int lns в функции betsy() и int lns в функции pam(), как и положено, разные?
0
Tulosba
:)
Эксперт С++
4396 / 3232 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
20.07.2014, 13:40 #24
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от gru74ik Посмотреть сообщение
А переменные int lns в функции betsy() и int lns в функции pam(), как и положено, разные?
Честно говоря, не понимаю, в чем вообще затруднение в понимании.
Существование фактических аргументов функции (вышеупомянутые переменные) разнесено по времени.
И нет совершенно никак объективных причин, почему бы не использовать ту же самую память (с одинаковыми адресами) в разные моменты времени.

Вызовите одну функцию из другой и увидите, что адреса будут разные. А всё потому, что они уже используются (должны существовать) одновременно.
1
gru74ik
Модератор
Эксперт CЭксперт С++
4196 / 1844 / 198
Регистрация: 20.02.2013
Сообщений: 4,990
Записей в блоге: 22
20.07.2014, 14:20  [ТС] #25
Цитата Сообщение от Tulosba Посмотреть сообщение
Существование фактических аргументов функции (вышеупомянутые переменные) разнесено по времени.
И нет совершенно никак объективных причин, почему бы не использовать ту же самую память (с одинаковыми адресами) в разные моменты времени.
То, что требовалось! Покорнейше благодарю, всё встало на свои места.
0
castaway
Эксперт С++
4888 / 3023 / 370
Регистрация: 10.11.2010
Сообщений: 11,080
Записей в блоге: 10
Завершенные тесты: 1
20.07.2014, 15:27 #26
gru74ik, да, в нём тоже.

Добавлено через 19 минут
Psilon, всегда считал и сейчас считаю что разницы нет, т.к. вызвать функцию через указатель можно только одним способом в конечном итоге.
2
Psilon
Master of Orion
Эксперт .NET
5908 / 4805 / 634
Регистрация: 10.07.2011
Сообщений: 14,407
Записей в блоге: 5
Завершенные тесты: 4
20.07.2014, 16:44 #27
Tulosba, эмм, что? Вот вызовы по-очереди, адреса все равно разные. Изменяем этот метод:
C++
1
2
3
4
5
6
template <typename FuncPtr>
void estimate(int lines, FuncPtr pf)
{
    using namespace std;
    cout << "Func adress is\t" << pf << endl;
}
получаем:
C++
1
2
3
4
5
6
How many lines of code do you need? 10
Here's Betsy's estimate:
Func adress is  001310E1
Here's Pam's estimate:
Func adress is  001312F3
Для продолжения нажмите любую клавишу . . .
как бы разные адреса жеж. Или я неправильно вопрос понял
0
Tulosba
:)
Эксперт С++
4396 / 3232 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
20.07.2014, 20:21 #28
Psilon, когда я писал ответ на вопрос ТС из сообщения #23 я опирался на код из сообщения #6. В частности на строки 37 и 48.
Т.е. речь об адресах фактических аргументов функций, которые (аргументы) будут на стеке.
1
Psilon
Master of Orion
Эксперт .NET
5908 / 4805 / 634
Регистрация: 10.07.2011
Сообщений: 14,407
Записей в блоге: 5
Завершенные тесты: 4
20.07.2014, 21:35 #29
Tulosba, а, ну это логично. В принципе, если один поток всегда у процесса, то тогда первый аргумент будет всегда иметь один и тот же адрес для всех функций
0
20.07.2014, 21:35
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.07.2014, 21:35
Привет! Вот еще темы с ответами:

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

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

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

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


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

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

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