Объявления указателей | Microsoft Learn
- Статья
- Чтение занимает 3 мин
Объявление указателя именует переменную указателя и задает тип объекта, на который указывает переменная. Переменная, объявленная как указатель, содержит адрес памяти.
Синтаксис
declarator
:
pointer
необ.direct-declarator
direct-declarator
:
identifier
(
declarator
)
direct-declarator
[
constant-expression
opt]
direct-declarator
(
parameter-type-list
)
direct-declarator
(
identifier-list
opt)
pointer
:
*
type-qualifier-list
необ.
*
type-qualifier-list
необ.pointer
type-qualifier-list
:
type-qualifier
type-qualifier-list
type-qualifier
задает type-specifier
тип объекта , который может быть любым базовым типом, типом структуры или объединения. Переменные указателя также могут указывать на функции, массивы и другие указателям. (Дополнительные сведения об объявлении и интерпретации более сложных типов указателей см. в разделе Интерпретация более сложных деклараторов.)
Создавая type-specifier
void
, можно отложить спецификацию типа, на который ссылается указатель. Этот элемент называется «указатель на void
» и записывается как void *
. Переменная, объявленная как указатель на void
, может использоваться для указания на объект любого типа. Однако для того чтобы выполнять большинство операций с указателем или объектом, на который он указывает, тип, на который он указывает, должен быть явно задан для каждой операции. (Переменные типа char *
и типа void *
совместимы с присваиваниями без приведения типов.) Такое преобразование можно выполнить с помощью приведения типа. Дополнительные сведения см. в разделе Преобразования приведения типов.
Может type-qualifier
быть либо const
, либо volatile
, либо и то, и другое. Эти ключевые слова указывают, соответственно, что указатель не может быть изменен самой программой (const
), или что указатель может быть изменен каким-либо процессом, не зависящим от программы (volatile
). Дополнительные сведения о ключевых словах const
и volatile
см. в статье Квалификаторы типов.
Имя declarator
переменной и может включать модификатор типа. Например, если declarator
представляет массив, тип указателя изменяется так, чтобы он был указателем на массив.
Можно объявить указатель на структуру, объединение или тип перечисления, прежде чем определять тип структуры, объединения или перечисления. Указатель объявляется с помощью структуры или тега union, как показано в примерах. Такие объявления разрешены, так как компилятору не нужно знать размер структуры или объединения, чтобы выделить пространство для переменной указателя.
Примеры
В следующих примерах показаны объявления указателей.
char *message; /* Declares a pointer variable named message */
Указатель message
указывает на переменную с char
типом .
int *pointers[10]; /* Declares an array of pointers */
Массив pointers
содержит 10 элементов; каждый элемент является указателем на переменную с int
типом .
int (*pointer)[10]; /* Declares a pointer to an array of 10 elements */
Переменная pointer
указывает на массив с 10 элементами. Каждый элемент в этом массиве имеет тип int
.
int const *x; /* Declares a pointer variable, x, to a constant value */
Указатель x
можно изменить, чтобы он указывал на другое int
значение, но не может быть изменено значение, на которое он указывает.
const int some_object = 5 ; int other_object = 37; int *const y = &fixed_object; int volatile *const z = &some_object; int *const volatile w = &some_object;
Переменная y
в этих объявлениях объявляется как постоянный указатель на int
значение. Значение, на которое он указывает, можно изменить, но сам указатель всегда должен указывать на одно и то же расположение: адрес fixed_object
. Аналогичным образом является z
указателем константы, но он также объявляется для указания на int
объект , значение которого не может быть изменено программой. Описатель volatile
указывает, что, хотя значение const int
объекта , на которое указывает z
, не может быть изменено программой, оно может быть изменено процессом, выполняющимся параллельно с программой. Объявление w
указывает, что программа не может изменить значение, на которое указывает, и что программа не может изменить указатель.
struct list *next, *previous; /* Uses the tag for list */
В этом примере объявляют две переменные указателя (next
и previous
), указывающие на тип list
структуры . Это объявление может отображаться перед определением list
типа структуры (см. следующий пример), если list
определение типа имеет ту же видимость, что и объявление.
struct list { char *token; int count; struct list *next; } line;
Переменная line
имеет тип структуры с именем list
. Тип list
структуры состоит из трех элементов: первый элемент является указателем на char
значение, второй — int
значением, а третий — указателем на другую list
структуру.
struct id { unsigned int id_no; struct name *pname; } record;
Переменная record
имеет тип id
структуры . pname
объявляется как указатель на другой тип структуры с именем name
. Это объявление может появиться перед определением name
типа.
См. также
Деклараторы и объявления переменных
Указатели в C++
Админ сайта Разработка на C++ Просмотров: 454
User Rating: 0 / 5
Рейтинг
(0)
В этой статье мы с вами рассмотрим понятие указателя в языке C++. Указатель (англ. pointer) в C++ — это переменная, которая содержит адрес памяти другой переменной. Как и любая другая переменная, указатель должен быть сначала объявлен перед тем, как вы начнёте его использовать.
Давайте сразу посмотрим на небольшой пример использования указателя в программе на C++, чтобы прояснить всё вышесказанное:
#include <iostream> using namespace std; int main() { // объявляем три переменные целого типа с именами a, b и c int a = 10, b = 20, c = 30; // объявляем переменную-указатель с именем p int* p; // выводим на экран консоли значения всех трёх переменных cout << "The value of 'a' is: " << a << endl; cout << "The value of 'b' is: " << b << endl; cout << "The value of 'c' is: " << c << endl; // присваиваем указателю значение адреса памяти, по которому хранится значение для переменной a p = &a; cout << "Pointer address is currently " << p << endl; // выводим значение указателя (это адрес памяти для переменной a) cout << "Pointer value is currently " << *p << endl; // выводим значение "содержимого" по тому адресу памяти, который хранит сейчас p // присваиваем указателю значение адреса памяти, по которому хранится значение для переменной b p = &b; cout << "Pointer address is currently " << p << endl; // выводим значение указателя (это адрес памяти для переменной b) cout << "Pointer value is currently " << *p << endl; // выводим значение "содержимого" по тому адресу памяти, который хранит сейчас p // присваиваем указателю значение адреса памяти, по которому хранится значение для переменной c p = &c; cout << "Pointer address is currently " << p << endl; // выводим значение указателя (это будет адрес памяти для переменной c) cout << "Pointer value is currently " << *p << endl; // выводим значение "содержимого" по тому адресу памяти, который хранит сейчас p }
Я специально снабдил код примера комментариями, чтобы каждая строка была полностью понятна, но всё же остановлюсь на ключевых моментах этого примера. Вначале мы объявили три целочисленных переменных с именами a, b и c, проинициализировав их значениями 10, 20 и 30, соответственно. Дальше мы объявили переменную-указатель с именем p. Как видите, в её объявлении указан тип int*, что означает «указатель на значение типа int». Как можно видеть, в объявлении переменной p
мы сначала не присваиваем ей никакого конкретного значения, это значит, что p будет содержать какое-то непредсказуемое значение, т.е. какой-то адрес, который не указывает на что-то конкретное. Обращаться к переменной-указателю на этой стадии нельзя: если вы попытаетесь использовать переменную-указатель до её инициализации, компилятор C++ не позволит этого сделать и выдаст ошибку, а такая программа у вас просто не скомпилируется.Дальше мы просто выводим значения наших переменных a, b и c на экран консоли. Это нужно для последующей части нашей программы-примера, чтобы сравнить результаты доступа к переменным с помощью нашей переменной-указателя p. После этого мы присваиваем нашей переменной p значение адреса переменной a:
p = &a;
Этим присвоением мы как бы «настраиваем» переменную-указатель p на то, чтобы она указывала на переменную a. Дальше идут две интересных строки с выводом на консоль, где мы вначале выводим содержимое самой переменной p, а после этого обращаемся к содержимому ячейки памяти, на которую указывает p посредством указания символа-звёздочки перед p, т.е. *p:
cout << "Pointer address is currently " << p << endl; // выводим значение указателя (это адрес памяти для переменной a) cout << "Pointer value is currently " << *p << endl; // выводим значение "содержимого" по тому адресу памяти, который хранит сейчас p
Такая запись *p называется разыменованием указателя.
Как вы уже, наверное, поняли, разыменование необходимо для того, чтобы обратиться к самим данным, на которые указывает в текущий момент времени переменная-указатель.Оставшаяся часть программы делает аналогичную «перенастройку» переменной-указателя p на две другие переменные b и c и также выводит на экран консоли значения адресов этих переменных и значения самих переменных.
После запуска этой программы у меня на экране консоли отобразилось следующее:
The value of 'a' is: 10
The value of 'b' is: 20
The value of 'c' is: 30
Pointer address is currently 00CFF91C
Pointer value is currently 10
Pointer address is currently 00CFF910
Pointer value is currently 20
Pointer address is currently 00CFF904
Pointer value is currently 30
Обратите внимание, в моём случае адреса памяти для переменных a, b и c
Напоследок запомните следующие важные моменты про указатели в языке C++:
- Переменная-указатель всегда хранит адрес памяти, на который она указывает, а не сами данные.
- Для объявления переменной-указателя необходимо указать тип данных, на которые будет указывать указатель, затем символ-звёздочку ( * ) и после этого имя самой переменной. Например, чтобы объявить переменную-указатель с именем x на тип данных char, используется запись: char* x;
- Для разыменования указателя применяется символ-звёздочка ( * ), идущий перед именем переменной-указателя. Например, если ваша переменная-указатель имеет имя x, то её разыменование записывается как *x
- Для инициализации переменной-указателя используется ссылка ( с помощью & ) на какую-то объявленную переменную в Вашей программе. К примеру, если у вас уже была объявлена другая переменная с именем y, и её тип данных char, то можно проинициализировать указатель x следующим образом: x = &y;
- Не пытайтесь произвести разыменование переменной-указателя перед тем, как присвоите переменной корректное значение адреса какой-то объявленной переменной соответствующего типа.
Попробуйте выполнить следующие упражнения для закрепления темы указателей в языке C++:
- Объявите в своей программе три переменных x, y и z с типом double. Проинициализируйте их какими-то значениями на свой вкус. Также объявите три переменных-указателя с именами px, py, pz и проинициализируйте их таким образом, чтобы они указывали на x, y и z, соответственно. Выведите значения указателей px, py, pz (адреса памяти) на экран консоли. Также выведите на консоль значения самих переменных x, y и z с помощью доступа к ним через переменные-указатели px, py и pz и их разыменование. После этого присвойте указателю pz адрес переменной x, а указателю px присвойте адрес переменной z. Выведите на экран консоли результат разыменования для px и pz.
- C++
- Обучение C++
- Назад
- Вперед
go — Как получить указатель интерфейса
Задавать вопрос
спросил
Изменено 3 года, 3 месяца назад
Просмотрено 628 раз
Трудно объяснить, но как я могу получить указатель что-то , реализующее какой-то интерфейс?
Рассмотрим код ниже:
основной пакет Импортировать ( "ФМТ" "небезопасно" ) тип Интерфейсный интерфейс { Пример() } введите структуру StructThatImplementsInterface { } func (i *StructThatImplementsInterface) Пример() { } введите структуру StructThatHasInterface { я Интерфейс } основная функция () { sameInterface := &StructThatImplementsInterface{} struct1 := StructThatHasInterface{i: тот жеИнтерфейс} struct2 := StructThatHasInterface{i: тот жеИнтерфейс} Проблема здесь(&struct1) Проблема здесь(&struct2) } func TheProblemIsHere(s *StructThatHasInterface) { fmt. Printf("Указатель от Printf: %p \n", s.i) fmt.Printf("Указатель от Usafe: %v \n", unsafe.Pointer(&s.i)) }
https://play.golang.org/p/HoC5_BBeswA
Результат будет:
Указатель от Printf: 0x40c138 Указатель от Usafe: 0x40c140 Указатель от Printf: 0x40c138 Указатель от Usafe: 0x40c148
Обратите внимание, что Printf
получает одинаковое значение (поскольку оба StructThatHasInterface
используют один и тот же sameInterface
). Однако unsafe.Pointer()
возвращает разные значения.
Как я могу получить тот же результат, что и Printf
без использования fmt
, а отразить
если возможно?
- go
- небезопасные указатели
4
В текущей версии Go значение интерфейса состоит из двух слов. Конкретное значение или указатель на конкретное значение хранится во втором слове. Используйте следующий код, чтобы получить второе слово как uintptr
:
u := (*[2]uintptr)(unsafe.Pointer(&s.i))[1]
Этот код небезопасен и не гарантируется, что он будет работать в будущем.
Поддерживаемый способ получения указателя:
u := Reflect.ValueOf(s.i).Pointer()
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google
Зарегистрироваться через Facebook
Зарегистрируйтесь, используя электронную почту и пароль
Опубликовать как гость
Электронная почта
Требуется, но не отображается
Опубликовать как гость
Электронная почта
Требуется, но не отображается
Стрелка | Этот указатель показывается чаще всего. Он используется для указания и выбора элементов, перемещения полос прокрутки, изменения размера окон и многого другого. Если вы потеряете след указателя на экране, быстро переместите палец по трекпаду или быстро переместите мышь — указатель ненадолго увеличится, чтобы его было лучше видно. При желании вы можете отключить эту функцию или изменить размер и цвет указателя. Выберите меню Apple > «Системные настройки», нажмите «Универсальный доступ» на боковой панели, нажмите «Экран» справа, затем измените настройки в разделе «Указатель». (Возможно, вам придется прокрутить вниз.) Открыть настройки дисплея для специальных возможностей для меня | ||||||||||
Poof | Указывает, что перетаскиваемый элемент исчезнет, когда вы отпустите кнопку. Если элемент является псевдонимом, его оригинал не удаляется. | ||||||||||
Копировать | Появляется, когда вы щелкаете файл или папку, удерживая клавишу Option, и указывает, что при перетаскивании элемента будет создана его копия в новом месте, а не перемещение. | ||||||||||
Псевдоним | Появляется, когда вы щелкаете элемент, удерживая клавиши Option-Command, и указывает, что при перетаскивании элемента будет создан псевдоним для элемента. | ||||||||||
Двутавровая балка | Появляется при выборе и вставке текста. | ||||||||||
Перекрестие | Появляется при выборе прямоугольной области на изображении. | ||||||||||
Указывающая рука | Появляется, когда указатель мыши находится над ссылкой на веб-страницу, документ или другой элемент. | ||||||||||
Открытая рука | Появляется при наведении указателя мыши на элемент, который можно перемещать и изменять в определенных пределах, например текст в ячейке электронной таблицы или строку таблицы в документе. | ||||||||||
Закрытая рука | Появляется, когда вы перемещаете и корректируете элемент в определенных пределах — например, текст в ячейке электронной таблицы или строку таблицы в документе. | ||||||||||
Переместить влево | Указывает, что боковая панель, панель инструментов, окно или другое место могут быть перемещены и изменены влево. | ||||||||||
Переместить вправо | Указывает, что боковую панель, панель инструментов, окно или другое место можно переместить вправо и изменить их размер. | ||||||||||
Перемещение влево или вправо | Указывает, что боковую панель, панель инструментов, окно или другое место можно перемещать и изменять размер влево или вправо. | ||||||||||
Переместить вверх | Указывает, что боковую панель, панель инструментов, окно или другое место можно перемещать и увеличивать в размере. | ||||||||||
Переместить вниз | Указывает, что боковую панель, панель инструментов, окно или другое место можно переместить и изменить размер вниз. | ||||||||||
Переместить вверх или вниз | Указывает, что боковую панель, панель инструментов, окно или другое место можно перемещать и изменять размер вверх и вниз. | ||||||||||
Перекрестие выбора снимка экрана | Указывает, что вы можете перетаскивать, чтобы выбрать то, что вы хотите включить в снимок экрана. | ||||||||||
Скриншот окна и меню камеры | Указывает, что на снимке экрана будет все окно или команды в меню. | ||||||||||
Запрещено | Указывает, что перетаскиваемый элемент не может быть помещен в текущее местоположение. Оставить комментарий
|