c++ — Чем отличаются ссылки от указателей в С++
Ссылки проще понять в сравнении с указателями. По сути, это те же указатели, но немного измененные.
Напишу только про обычные ссылки («lvalue-ссылки» &
). Про «rvalue-ссылки» &&
— читать отдельно.
Ссылки всегда разыменовываются автоматически (после того, как были созданы):
int x = 0; int x = 0; int *y = &x; int &y = x; *y = 42; y = 42; // Не нужно разыменование.
Следствие: Ссылку нельзя «перенацелить» на другой объект, после того, как она создана.
Если для указателя можно написать
y = &z;
, то для ссылки присваивание меняет объект, на который она ссылается, а не ее саму.Следствие: Ссылку обязательно инициализировать сразу при создании.
int *z; /* ок */ int &z; // Ошибка компиляции.
Следствие: Ссылки не бывают константными.
Поскольку их и так нельзя менять, дополнительный
const
не имеет смысла и запрещен.int *const x
— «x
— константный указатель на неконстантныйint
«. Ноint &const x
— ошибка компиляции.Не путать с
const int *x
иconst int &x
— неконстантный указатель/ссылка на константныйint
. Тут оба варианта легальны.
Ссылки инициализируются не адресом, а самим объектом (см. пример выше).
Разница только в способе записи, эффект на самом деле одинаковый.
Следствие: Ссылки не бывают нулевыми.
Указатель можно инициализировать
nullptr
— нулевым адресом. А поскольку ссылка инициализируется не адресом, туда указатель не подойдет.Попытка создать нулевую ссылку (пример:
int *x = nullptr; int &y = *x;
) вызывает неопределенное поведение. Но компиляторы обычно никак не защищают от этого (вероятнее всего, крашнет при использовании ссылки, а не при создании).Но поскольку это UB (т.е. «undefined behavior», т.е. «неопределенное поведение»), проверки а-ля
&ссылка == nullptr
не имеют никакого смысла, поскольку могут быть выброшены компилятором как всегда ложные.
И указатели, и ссылки часто используют как параметры функций — когда передавать по значению не хочется (либо потому, что нужно изменить параметр и видеть изменения снаружи функции, либо потому, что тип параметра дорого копировать). Соответственно, чаще всего указатели — для опциональных параметров (вместо которых можно передать ноль), а ссылки — для обязательных.
Чтобы передать в функцию массив, традиционно используют указатель на первый элемент, хотя чисто с точки зрения языка, ссылка на первый элемент ничем не хуже.
Некоторые не любят использовать неконстантные ссылки в параметрах. Дескать, нагляднее писать &
при вызове, чтобы сразу видеть, что объект меняется.
И указатели и ссылки нельзя инициализировать rvalue (грубо говоря, временными объектами, у которых компилятор не дает взять адрес):
int *x = &42; // ошибка компиляции, сразу на `&`. int &y = 42; // ошибка компиляции
- Исключение: Ссылки на константные типы — можно.
const int &z = 42; // ок
Дальше идут тонкости.
Ссылки продляют время жизни временных объектов.
const int &x = 42; int y = x;
Этот пример легален. Временный объект, на который указывает ссылка, продляет свое время жизни до времени жизни ссылки.
Но в этом правиле много исключений, например при возврате ссылки из функции это не действует. Никаких принципально новых возможностей эта фича не дает, поэтому проще вообще не пользоваться.
Ссылки не являются объектами.
Это больше формальность в стандарте, и тут нужно объяснение.
Объект — это просто экземпляр какого-то типа, с именем или без. Например,
int x
— объект типаint
, и42
— тоже. (Исключение: функции — не объекты.)Переменная — это, грубо говоря, объект с именем.
int x
— переменная, а42
— нет. (Хотя исключения есть. Например, безымянные параметры функций — тоже переменные.)И второе исключение: ссылки — это переменные, но не объекты. Т.е.
int &x
— переменная но не объект, аint x
— одновременно и переменная и объект.Поэтому, более точное определение переменной — это «то, что было объявлено (если это не функция)». Т.е.
— переменная, если где-то выше есть объявлениеint x;
. А42
— нет, потому что для нее ничего такого нет.Следствие: Формально, у ссылок нет адресов.
&ссылка
выдает адрес не самой ссылки, а того, на что она указывает (это следует из того, что ссылки разыменовываются автоматически).Можно положить ссылку в структуру, и взять адрес структуры. Технически, по этому адресу как раз будет лежать ссылка (в виде указателя), но формально — по этому адресу непонятно что.
- Следствие: Менять какие-то байтики по «адресу» ссылки — UB.
Следствие: Не бывает указателей на ссылки, массивов ссылок.
Выражения не могут иметь типы-ссылки.
Это тоже больше формальность.
У внимательного читателя мог возникнуть вопрос: Если не бывает объектов-ссылок, то чем будет являться возвращенная из функции ссылка? Ведь не переменной, имени-то у нее нет, и объявлена она не была.
Сначала поясняю, что такое выражение. Классическое определение — это «операнды, соединенные операторами». Т.е.
1 + 1
,(2 * 3) + 4
, и т.п. Отдельные операнды — это тоже выражения, например42
илиx
(если выше естьint x;
).Выражение — это часть исходного кода программы (грамматический термин), а не то, что существует в памяти (то — объекты).
Выражение ссылаются на объекты. Например,
1 + 1
ссылается на временный объект int со значением 2. Аx
ссылается на объект и переменнуюint x;
(если такая объявлена выше).Rvalue и lvalue — это свойства выражений (т.
н. «категория выражения»), а «временный» и «не временный» — свойства объектов.Так вот, выражения не могут иметь типы-ссылки.
Т.е. если имеем
int &x
, то выражениеx
— это lvalue типаint
(ссылкой оно быть не может). Аналогично, если естьint y
, то выражениеy
— тоже lvalue типаint
.Аналогично, если имеем
int &x()
, тоx()
— lvalue типа int. А дляint y()
,y()
— rvalue типа int.
правила и примеры. Что такое Present Simple и когда употребляется.
Простое время в английском языке — лучший способ рассказать собеседнику о своих привычках и предпочтениях, о том, что мы умеем делать или делаем каждый день. Это одно из самых часто встречающихся времен в повседневной речи, поэтому важно понять и изучить его с самого начала.
Сегодня поговорим о том, что такое Present Simple Tense, распространенные случаи употребления, узнаем основные правила образования Present Simple, какие существуют маркеры времени и рассмотрим примеры предложений.
Что такое Present Simple?
Это простое настоящее время, обозначающее действие в самом широком смысле этого слова. Одна из самых распространенных и простых форм в английском языке для описания действий.
Действия могут быть связаны с привычками, хобби, ежедневным событием вроде подъема по утрам или чем-то, что случается регулярно.
Как образуется Present Simple?
Нет ничего проще, чем поставить глагол в форму Present Simple. Для этого нужно убрать у глагола в инфинитиве частицу «to» и поставить глагол после подлежащего. Это и есть основное правило Present Simple.
Утверждение:
I / We / You / They + V
She / He / It + V + s (es)
I go to work every day — Я хожу на работу каждый день.
They usually play tennis every weekend
She brings me coffee every morning — Она приносит мне кофе каждое утро.
It snows in winter — Зимой идет снег.
ВАЖНО: В Present Simple форма глагола практически всегда совпадает с изначальной. Исключение составляет третье лицо единственного числа (he / she / it) — к нему прибавляется окончание -s:
I ride — She rides
I dream — He dreams
Если глагол оканчивается на -s, -ss, -sh, -ch, -x, -o, то к нему прибавляется окончание -es
I wish — She wishes
I teach — She teaches
Если глагол оканчивается на -y, а ему предшествует согласная, то к нему прибавляется окончание -es, но -y заменяется на -i
I try — She tries
I fly — He flies
Если глагол оканчивается на -y, а ему предшествует гласная, то к нему также прибавляется окончание -s, но -y не меняется.
I play — She plays
I stay — He stays
Отрицание:
Чтобы составить отрицательное предложение — нужно поставить вспомогательный глагол между подлежащим и глаголом.
I / We / You / They + do not (don’t) + V
She / He / It + does not (doesn’t) + V
I don’t go to school every day — Я не хожу в школу каждый день
They don’t drink beer — Они не пьют пиво
She doesn’t like the weather in London
He doesn’t drive the car — Он не водит машину
Отрицание также можно выразить при помощи отрицательных местоимений и наречий.
Nobody speaks Arabic — Никто не говорит по-арабски
I do nothing — Я ничего не делаю
Вопрос:
При составлении вопросительных предложений вспомогательный глагол ставится перед подлежащим и последующим глаголом. Обычно — в начало предложения.
Do + I / we / you / they + V ?
Does + she / he / it + V ?
Do you like pizza? — Тебе нравится пицца?
Do they play football? — Они играют в футбол?
Does she learn Russian? — Она изучает русский язык?
Does he live in Spain? — Он живет в Испании?
Иногда в вопросительном предложении употребляются question words (вопросительные слова) и фразы, которые помогают задать более точный и корректный вопрос собеседнику.
К таким словам относятся: how long (как долго), why (почему), where (где) и другие. Как и в других временах, они ставятся в самом начале предложения перед вопросительной конструкцией Present Simple.
QW + do (does) + I / We / You / They / She / He / It + V ?
Where does he live in Prague? — Где он живет в Праге?
Why do you drink green tea? — Почему ты пьешь зеленый чай?
Когда в предложении с Present Simple появляется вспомогательный глагол — у основного глагола пропадает окончание -s. Считайте, что это такой своеобразный «магнит», который «перетягивает» к себе это окончание. Это касается отрицательной и вопросительной форм Present Simple.
ВАЖНО: иногда вспомогательный глагол do / does можно встретить и в утвердительных предложениях, чтобы добавить экспрессии и яркости высказыванию.
I do want to try this — Я действительно хочу это попробовать
Mary does know how to cook — Мэри действительно умеет готовить
Глагол to be в Present Simple
Глагол to be (быть) всегда является особенным и его употребление во времени Present Simple зависит от подлежащего. Он имеет 3 разных формы:
- am (для 1-го лица единственного числа: I)
- is (для 3-го лица единственного числа: she / he / it)
- are (для 1-го, 2-го и 3-го лица множественного числа: we / you / they)
I am ready — Я готов
She is ready — Она готова
We are ready — Мы готовы
Когда используется Present Simple?
Present Simple используется в описании действий, которые происходят постоянно, на регулярной
основе, но не привязаны к моменту речи.
Употребление Present Simple уместно в тех случаях, когда мы хотим рассказать о нашей ежедневной рутине, достоверно известных фактах, действиях в широком смысле слова или расписании поездов.
Регулярные, повторяющиеся действия:
I often go to the bar — Я часто хожу в бар
They play music every Sunday — Они играют музыку каждое воскресенье
Действие в широком смысле слова (без привязки к моменту речи):
I live in Dublin — Я живу в Дублине.
She speaks Chinese — Она говорит по-китайски.
Факты, о которых знают все:
The Earth rotates around its axis — Земля вращается вокруг своей оси.
Moscow is the largest city in Russia — Москва самый большой город в России
Будущие действия, которые произойдут согласно расписанию:
The airplane takes off at 4.30 am — Самолет взлетит в 4.30 утра.
The train leaves at 9 pm tomorrow — Поезд отходит завтра в 9 вечера.
Рецепты и инструкции (используется вместо повелительного наклонения):
You push the red button to turn on the radio — Нажмите на красную кнопку, чтобы включить радио
First you turn left and then you go down the street — Сперва поверните налево, затем идите до конца улицы
При перечислении каких-то действий и их определенной последовательности также используется время Present Simple
You take the bus into the city center and then you take a taxi to the restaurant — Вы едете на автобусе до центра города, а затем берете такси до ресторана.
Иногда время Present Simple используется в отношении прошедшего времени. Например, в заголовках газет (указывают на факт произошедшего действия) или в рассказе о событии (когда мы говорим о ком-то и его действиях).
The bus with American tourists crashes in India — В Индии разбился автобус с американскими туристами
I met John last week. He comes to me and says: “Hello, old friend” — На прошлой неделе я встретил Джона. Он подошел ко мне и сказал: «Привет, старый друг»
Маркеры времени Present Simple
Для того, чтобы лучше сориентироваться где и когда употребляются глаголы Present Simple — обратите внимание на особые маркеры в тексте.
Такими «маячками» для Present Simple являются наречия (often, always, usually, etc.) и указатели времени (every day, in the morning, on Fridays, etc.).
She always drinks coffee in the morning — Она всегда пьет кофе по утрам
I usually wake up at 6 am — Обычно я просыпаюсь в 6 утра
They often talk about sport — Они часто говорят о спорте
I check my smartphone every 15 minutes — Я проверяю свой телефон каждые 15 минут
He takes a shower twice a day — Он принимает душ два раза в день
On Mondays we go to the central park — По понедельникам мы ходим в центральный парк
He comes here sometimes — Иногда он приходит сюда
Примеры предложений с Present Simple:
Утвердительные предложения:
I read a book every evening — Я читаю книгу каждый вечер
He likes to be polite — Ему нравится быть вежливым
It takes two hours to fly from Berlin — Полет из Берлина займет два часа
Cats like milk — Кошки любят молоко
Отрицательные предложения:
I don’t buy food in the supermarket — Я не покупаю еду в супермаркете
He doesn’t play piano very well — Он не очень хорошо играет на пианино
They don’t read books — Они не читают книги
Duck don’t eat fish — Утки не едят рыбу
Вопросительные предложения:
Do you live in Paris? — Ты живешь в Париже?
Does she play in a band? — Она играет в группе?
Do you eat fish? — Ты ешь рыбу?
Do they like coffee? — Им нравится кофе?
Понимание указателей и объединенных списков в Python
Почему dummy. next ссылается на cur?
Это не .
Изначально создается дополнительный узел, чтобы после него можно было связать узлы из исходных списков. dummy
и cur
оба являются именами для этого узла в начале функции.
По мере выполнения функции cur
становится именем для разных узлов, но dummy
остается именем первоначально созданного узла.
Функция возвращает dummy.next
, потому что функция работала путем последовательного связывания узлов после этого узла, поэтому dummy.next
ссылается на ( не «указывает на») первый из этих связанных узлов.
, и нет явного перемещения указателя dummy в начало cur, как в языке типа C.
В Python нет указателей . Кроме того, cur
является узлом ; у него нет «головы». В этой реализации нет объектов, которые явно представляют весь список — только объекты, представляющие узлы, так что список неявно представляет собой какой-то узел вместе со всеми другими, достижимыми из него.
пустышка
начиналась как имя вновь созданного узла. Нет необходимости переназначать фиктивный
в качестве имени «головы списка», потому что это было имя для этого узла, никогда не переставало быть именем для этого узла, и этот узел использовался как . предшественник для списка. (Поскольку этот узел на самом деле не является частью предполагаемого результата, мы должны пропустить его при возврате.)
Почему мы обновляем cur дважды в последовательных строках?
Во-первых, важно понимать, что мы этого не делаем. Подробно:
Сначала мы устанавливаем cur.next равным одному из списков, но затем мы устанавливаем сам cur равным тому же списку в следующей строке?
Изменение значения cur.next
не то же самое, что установка cur
. То же самое происходит, например, с элементами списка:
a = [1, 2, 3] б = а # изменение элемента a БУДЕТ изменить то, что мы видим в b: а[0] = 4 печать (б) # ЗАМЕНА `a` НЕ изменит то, что мы видим в b: a = 'привет, мама' # нам даже не нужно заменять его другим списком печать (б)
Запись b = a
не копирует список. Это означает, что b
— это другое имя для того же объекта , что и a
. Если мы изменим на эту штуку , то, очевидно, мы увидим изменение, если проверим b
. Если мы сделаем a
именем чего-то другого , тогда это , а не повлияет на b
, потому что b
по-прежнему является именем того, что было раньше.
Это то же самое, что и настоящие имена — или другие формы обращения — людей в реальном мире. Боб — младший сын Алисы. Когда Боб вырастает, Алиса наблюдает, как растет «мой младший сын», потому что это означает, что он тот же человек. Если Алиса родит еще одного мальчика и обнимет «моего младшего сына», Боб не почувствует объятий, потому что «мой младший сын» уже не означает того же человека.
Я не понимаю, зачем это нужно
Теперь можно рассмотреть назначение кода.
cur
— это имя, которое мы используем для «последнего узла списка, который мы создаем».
Поскольку мы добавляем узлы в список для его построения, со временем это должно ссылаться на разные узлы.
Выполняя cur.next = ...
, мы связываем еще один узел после узла с именем cur
. Это поможет нам составить список, но теперь cur
больше не является именем последнего узла, потому что это все еще имя узла, который он называл раньше, и этот узел больше не является последним узлом, потому что мы добавили узел.
Итак, после добавления узла мы переназначаем cur
для имени узла, который мы только что добавили.
Понимание указателей — Видеоруководство по C
Из курса: C: Структуры данных, указатели и файловые системы
Понимание указателей
“
— [Инструктор] Чтобы понять указатели, вы должны изучить переменные. В этом коде вы видите переменную Integer alpha. Сразу вы знаете три вещи об этом. Его тип данных, целое число. Его имя, альфа. И его значение, 27, назначено в строке 7. Вы также можете получить два других информативных факта о переменных в вашем коде. Количество байтов, которое он занимает в памяти, полученное по размеру оператора, который появляется в конце строки 9.. И расположение переменной в памяти, полученное с помощью оператора & в конце строки 10. Соберите и запустите. И здесь вы видите, что целочисленная переменная alpha содержит значение 27, что она занимает четыре байта памяти в этой системе и находится по адресу 0060FEFC. И этот адрес будет отличаться от компьютера к компьютеру, а также на одном и том же компьютере, когда вы запускаете код в разное время. Это не гарантия. Эти два элемента, размер переменной и ее расположение в памяти, связаны с концепцией указателей в языке C. Указатель — это переменная, которая содержит ячейку памяти. Это мое определение. Он избегает использования описания, указатель указывает на адрес, что верно, но лучше сказать, что указатель — это переменная, содержащая ячейку памяти. Место памяти чего? Что ж, указатель содержит ячейку памяти или адрес другой переменной в вашем коде. Поскольку указатель сам по себе является переменной, его можно изменить, каким-то образом изменив адрес. Указатель также может манипулировать данными, хранящимися по адресу, на который он ссылается. Указатели объявляются так же, как и любые другие переменные. У них есть тип данных и имя переменной. При объявлении переменной перед именем ставится звездочка. Теперь это единственный оператор указателя звездочки. Это не оператор умножения. Как и все переменные, указатель должен быть инициализирован перед использованием. Неинициализированный указатель приводит к проблемам. Чтобы инициализировать указатель, вы присваиваете ему адрес другой переменной в вашем коде, которая соответствует типу данных указателя. Итак, int для целых чисел, char для символов и так далее. Оператор амперсанд используется для получения адреса переменной. Возможно, вы видели, как этот оператор используется в функции сканирования F, а также в файле упражнений этого фильма.