Страшная тайна ;)
Mar. 4th, 2010 05:00 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Мне тут процитировали классическую задачку для кондовых сишников: написать объявление переменной, которая является "указателем на функцию, на указатель на..." - ну и далее какие-нибудь такие навороты. Знакомо?
Так вот, ежели этот блог читают студенты, которых мучают такими задачками,а также старички, которые решают такие задачки методом тыка, то открою страшную тайну: задачки такие решаются чисто механически. Схема такая:
1. Пишем какой-нибудь идентификатор
2. Далее в цикле:
- прочитав "указатель на..."
- ставим * слева
- прочитав "ссылка на..."
- ставим & слева
- прочитав "массив из..."
- ставим [] справа. если будет сказано количество элементов, пишем, в [] сколько их
- прочитав "... функция..."
- просто ставим () справа
- прочитав "...принимающая/принимающую..."
- готовимся писать в тех скобках, что поставили, услышав про функцию
- прочитав "...возвращающая/возвращающую..."
- готовимся писать слева
- прочитав название типа
- ставим его слева
3. В процессе на каждом шаге делаем такую проверку: если использовано слово "указатель/ссылка", а потом используется "массив" или "функция", то перед очередным шагом все заключаем в скобки. Например:
"указатель на массив..." (*x)[]
"указатель на функцию..." (*f)()
но:
"массив указателей..." *x[]
"функция, возвращающая указатель" *f()
- это связано с тем, что приоритет операций & и * ниже, чем [] и ()
4. добавляем ;
В большинстве случаев эта тупая метода прокатывает с первого раза. Если нет, разбиваем на части и используем typedef-ы.
Пример:
"Указатель на указатель на массив из двух указателей на указатель на int"
x
"Указатель на"
*x
"указатель на"
**x
" массив из" (правило 3!)
(**x)[]
"двух "
(**x)[2]
"указателей на"
*(**x)[2]
" указатель на"
**(**x)[2]
"int"
int **(**x)[2];
Так вот, ежели этот блог читают студенты, которых мучают такими задачками,
1. Пишем какой-нибудь идентификатор
2. Далее в цикле:
- прочитав "указатель на..."
- ставим * слева
- прочитав "ссылка на..."
- ставим & слева
- прочитав "массив из..."
- ставим [] справа. если будет сказано количество элементов, пишем, в [] сколько их
- прочитав "... функция..."
- просто ставим () справа
- прочитав "...принимающая/принимающую..."
- готовимся писать в тех скобках, что поставили, услышав про функцию
- прочитав "...возвращающая/возвращающую..."
- готовимся писать слева
- прочитав название типа
- ставим его слева
3. В процессе на каждом шаге делаем такую проверку: если использовано слово "указатель/ссылка", а потом используется "массив" или "функция", то перед очередным шагом все заключаем в скобки. Например:
"указатель на массив..." (*x)[]
"указатель на функцию..." (*f)()
но:
"массив указателей..." *x[]
"функция, возвращающая указатель" *f()
- это связано с тем, что приоритет операций & и * ниже, чем [] и ()
4. добавляем ;
В большинстве случаев эта тупая метода прокатывает с первого раза. Если нет, разбиваем на части и используем typedef-ы.
Пример:
"Указатель на указатель на массив из двух указателей на указатель на int"
x
"Указатель на"
*x
"указатель на"
**x
" массив из" (правило 3!)
(**x)[]
"двух "
(**x)[2]
"указателей на"
*(**x)[2]
" указатель на"
**(**x)[2]
"int"
int **(**x)[2];
no subject
Date: 2010-03-04 02:40 pm (UTC)no subject
Date: 2010-03-04 02:51 pm (UTC)И вы никогда не наблюдали сценку, когда опытный программер решает задачки этого типа методом тыка, не? ;)
no subject
Date: 2010-03-04 02:52 pm (UTC)Вроде это всё-тки совсем азы.
no subject
Date: 2010-03-04 03:00 pm (UTC)no subject
Date: 2010-03-04 03:06 pm (UTC)no subject
Date: 2010-03-04 03:12 pm (UTC)no subject
Date: 2010-03-04 03:38 pm (UTC)Например если немного понимаешь мысли, стоявшие за Си, никогда не перепутаешь int *f() и int (*f)().
Понимать нужно всего лишь две вещи:
- Операция () как и [] имеет более высокий приоритет, чем *. Проверочная конструкция:
int *f() = int* f().
(Из чего немедленно ясно, что в первом случае у нас функция, возвращающая указатели на целые числа.)
- Принцип подстановки: если а определено как int *a, то *а должно иметь тип int. Если f определено как int f(), то f() должно иметь тип int. Соответственно *f во втором случае должно иметь тот же тип, что и x в int x(). (Из чего немедленно ясно, что во втором случае у нас указатель на функцию, возвращающую целые числа.)
no subject
Date: 2010-03-04 04:02 pm (UTC)no subject
Date: 2010-03-04 04:15 pm (UTC)http://www.trizway.com/art/article/210.html (Классическая “Он чинит приёмники, думая” Р. Фейнмана.)
no subject
Date: 2010-03-04 06:13 pm (UTC)no subject
Date: 2010-03-04 06:16 pm (UTC)Как ни странно, не могу себе представить, чтобы я хорошо понимал, «как устроено», и при этом не мог сходу написать синтаксически верную конструкцию такого вот типа. Ну не знаю, может у меня мозги как-то криво работают.
no subject
Date: 2010-03-04 06:43 pm (UTC)no subject
Date: 2010-03-04 06:45 pm (UTC)no subject
Date: 2010-03-04 02:47 pm (UTC)no subject
Date: 2010-03-04 02:59 pm (UTC)"В перделе" ты, возможно, имеешь в виду то, что есть такие объекты-интерфейсы, которые кагбэ не имеют в себе данных (полей), а только методы (алгоритмы). Так это не так. Обычно в объекте-интерфейсе так или иначе спрятан адрес объекта-реализации, а в нем - все те самые данные. То есть, это чисто оформление такое, защищающее от некоторых проблем (а иногда создающее новые проблемы).
no subject
Date: 2010-03-04 03:28 pm (UTC)no subject
Date: 2010-03-04 03:38 pm (UTC)Первое - это "значение" или "экземпляр", второе - тип значения, оба они обзываются словом "структура".
no subject
Date: 2010-03-04 03:47 pm (UTC)--------------------
Кстати, возник личнный вопрос. Кинь мне на почту, чтобы ответить. Твою не нашёл.
no subject
Date: 2010-03-04 04:00 pm (UTC)--------
xoxox(САБАКА)list.ru
no subject
Date: 2010-03-04 04:15 pm (UTC)no subject
Date: 2010-03-04 06:11 pm (UTC)no subject
Date: 2010-03-04 02:51 pm (UTC)no subject
Date: 2010-03-04 03:02 pm (UTC)no subject
Date: 2010-03-04 06:12 pm (UTC)Обожаю такие штуки
no subject
Date: 2010-03-08 02:45 am (UTC)no subject
Date: 2010-03-14 05:57 pm (UTC)ведь там приходится обязательно писать имя класса и значек ::*
но зато за счет этого можно легко организовать замену майкрософтских propetries для членов класса стандартными средствами С++, даже не boost и не tr1