Указатели в C++: зачем нужны, когда использовать и чем отличаются

Указатели в C++ Программирование и разработка

Указатели в C++

Память компьютера — это длинный ряд ячеек. Размер каждой ячейки называется байтом. Байт — это пространство, занятое английским символом алфавита. Объект в обычном понимании — это последовательный набор байтов в памяти. Каждая ячейка имеет адрес, который представляет собой целое число, обычно записанное в шестнадцатеричной форме. Есть три способа доступа к объекту в памяти. Доступ к объекту можно получить с помощью так называемого указателя. Доступ к нему можно получить, используя так называемую ссылку. К нему по-прежнему можно получить доступ с помощью идентификатора. В этой статье основное внимание уделяется использованию указателей и ссылок. В C ++ есть заостренный объект и объект-указатель. У остроконечного предмета есть интересующий предмет. Объект-указатель имеет адрес указанного объекта.

Вам необходимо иметь базовые знания C ++, включая его идентификаторы, функции и массивы; чтобы понять эту статью.

У объекта-указателя и объекта-указателя есть свой идентификатор.

Оператор Address-Of, &

Это унарный оператор. Если за ним следует идентификатор, он возвращает адрес объекта идентификатора. Рассмотрим следующее объявление:

 int ptdInt;

Ниже приведен код, следующее выражение, вернет адрес, идентифицированный ptdInt:

 &ptdInt

Вам не нужно знать точный адрес (номер) при кодировании.

Оператор косвенного обращения, *

Это унарный оператор в контексте указателей. Обычно он печатается перед идентификатором. Если используется в объявлении идентификатора, то идентификатор является объектом-указателем, который содержит только адрес указанного объекта. Если используется перед идентификатором объекта-указателя, чтобы что-то вернуть, то возвращаемое значение является значением указанного объекта.

Создание указателя

Взгляните на следующий фрагмент кода:

 float ptdFloat;
float *ptrFloat;

ptrFoat = &ptdFloat;

Сегмент начинается с объявления указанного объекта ptdFloat. ptdFloat — это идентификатор, который просто идентифицирует объект с плавающей запятой. Ему мог быть присвоен реальный объект (значение), но в этом случае ему ничего не было присвоено. Далее в сегменте идет объявление объекта-указателя. Оператор косвенного обращения перед этим идентификатором означает, что он должен содержать адрес указанного объекта. Тип объекта, плавающий в начале оператора, означает, что заостренный объект является плавающим. Объект-указатель всегда имеет тот же тип, что и заостренный объект. ptrFoat — это идентификатор, который просто идентифицирует объект-указатель.

В последнем операторе кода адрес указанного объекта присваивается объекту-указателю. Обратите внимание на использование оператора адресации &.

Последний оператор (строка) выше показывает, что после объявления объекта-указателя без инициализации вам не нужен оператор косвенного обращения, когда вам нужно его инициализировать. Фактически, использование оператора косвенного обращения в третьей (последней) строке является синтаксической ошибкой.

Объект-указатель может быть объявлен и инициализирован указанным объектом в одной инструкции, как показано ниже:

 float ptdFloat;
float *ptrFoat = &ptdFloat;

Первая строка предыдущего сегмента кода и эта совпадают. Здесь вторая и третья строки предыдущего сегмента кода объединены в один оператор.

Обратите внимание, что в приведенном выше коде при объявлении и инициализации объекта-указателя необходимо использовать оператор косвенного обращения. Однако он не используется, если инициализация должна быть выполнена позже. Объект-указатель инициализируется адресом указанного объекта.

В следующем сегменте кода оператор косвенного обращения используется для возврата содержимого указанного объекта.

    int ptdInt = 5;
int *ptrInt = &ptdInt;

cout << *ptrInt << \n;

Выход 5.

В последнем предложении здесь оператор косвенного обращения использовался для возврата значения, на которое указывает идентификатор указателя. Таким образом, при использовании в объявлении идентификатор для оператора косвенного обращения будет содержать адрес указанного объекта. При использовании в выражении возврата в сочетании с идентификатором указателя оператор косвенного обращения возвращает значение указанного объекта.

Присвоение нуля указателю

Объект-указатель всегда должен иметь тип указанного объекта. При объявлении объекта-указателя должен использоваться тип данных указанного объекта. Однако значение десятичного нуля может быть присвоено указателю, как в следующем сегменте кода:

    int ptdInt = 5;
int *ptrInt;

ptrInt = 0;

or in the segment,

int ptdInt = 5;
int *ptrInt = 0;

В любом случае указатель (идентификатор) называется нулевым указателем; это означает, что он указывает в никуда. То есть у него нет адреса какого-либо указанного объекта. Здесь 0 — это десятичный ноль, а не шестнадцатеричный ноль. Шестнадцатеричный ноль будет указывать на первый адрес памяти компьютера.

Читайте также:  Скользящая средняя в Pandas

Не пытайтесь получить значение, на которое указывает нулевой указатель. Если вы попробуете это сделать, программа может скомпилироваться, но не запуститься.

Имя массива как постоянный указатель

Рассмотрим следующий массив:

int arr[] = {000, 100, 200, 300, 400};

Имя массива arr на самом деле является идентификатором, который имеет адрес первого элемента массива. Следующее выражение возвращает первое значение в массиве:

*arr

В случае с массивом оператор приращения ++ ведет себя иначе. Вместо добавления 1 он заменяет адрес указателя на адрес следующего элемента в массиве. Однако имя массива — это постоянный указатель; это означает, что его содержимое (адрес) не может быть изменено или увеличено. Итак, для увеличения начальный адрес массива должен быть назначен непостоянному указателю следующим образом:

int *ptr = arr;

Теперь ptr можно увеличивать, чтобы указывать на следующий элемент массива. ptr был объявлен здесь как объект-указатель. Без * здесь не было бы указателя; это будет идентификатор для хранения объекта типа int, а не для хранения адреса памяти.

Следующий сегмент кода, наконец, указывает на четвертый элемент:

    ++ptr;
++ptr;
++ptr;

Следующий код выводит четвертое значение массива:

    int arr[] = {000, 100, 200, 300, 400};

int *ptr = arr;

++ptr;
++ptr;
++ptr;

cout << *ptr << \n;

Выход 300.

Имя функции как идентификатор

Имя функции — это идентификатор функции. Рассмотрим следующее определение функции:

int fn()
{
cout << «seen» << \n;

return 4;
}

fn — идентификатор функции. Выражение,

& fn

возвращает адрес функции в памяти. fn похожа на заостренный объект. Следующее объявление объявляет указатель на функцию:

int (*func)();

Идентификатор указанного объекта и идентификатор объекта-указателя различаются. func — это указатель на функцию. fn — идентификатор функции. Итак, func может указывать на fn следующим образом:

func = &fn;

Значение (содержание) func — это адрес fn. Два идентификатора могли быть связаны с помощью оператора инициализации следующим образом:

int (*func)() = &fn;

Обратите внимание на различия и сходства в обработке указателей функций и скалярных указателей. func — указатель на функцию; это заостренный объект; он объявлен иначе, чем скалярный указатель.

Функцию можно вызвать с помощью,

fn()
or
func()

Его нельзя вызвать с помощью * func ().

Когда функция имеет параметры, во вторых скобках указаны типы параметров, и для них не обязательно должны быть идентификаторы. Следующая программа иллюстрирует это:

#include <iostream>
using namespace std;

float fn(float fl, int in)
{
return fl;
}

int main()
{

float (*func)(float, int) = &fn;

float val = func(2.5, 6);

cout << val << \n;

return 0;
}

C++ Reference

Ссылка в C ++ — это просто способ создать синоним (другое имя) для идентификатора. Он использует оператор &, но не так, как & используется для указателей. Рассмотрим следующий фрагмент кода:

    int myInt = 8;
int &yourInt = myInt;

cout << myInt << \n;
cout << yourInt << \n;

Результат:

8
8

Первый оператор инициализирует идентификатор myInt; т.е. myInt объявлен и содержит значение 8. Второй оператор создает новый идентификатор yourInt, синоним myInt. Для этого в объявлении между типом данных и новым идентификатором помещается оператор &. Операторы cout показывают, что два идентификатора являются синонимами. Чтобы вернуть значение в этом случае, вам не нужно ставить перед ним *. Просто используйте идентификатор.

Здесь myInt и yourInt — это не два разных объекта. Это два разных идентификатора, которые ссылаются (идентифицируют) одно и то же место в памяти, имеющее значение 8. Если значение myInt изменяется, значение yourInt также изменится автоматически. Если значение yourInt изменится, значение myInt также изменится автоматически.

Читайте также:  Как научиться программировать на C

Ссылки однотипные.

Ссылка на функцию

Так же, как у вас может быть ссылка на скаляр, вы также можете иметь ссылку на функцию. Однако кодирование ссылки на функцию отличается от кодирования ссылки на скаляр. Следующая программа иллюстрирует это:

#include <iostream>
using namespace std;

float fn(float fl, int in)
{
return fl;
}

int main()
{

float (&func)(float, int) = fn;

float val = func(2.5, 6);

cout << val << \n;

return 0;
}

Выход 2,5.

Обратите внимание на первый оператор в функции main, который делает func синонимом fn. Оба ссылаются на одну и ту же функцию. Обратите внимание на одноразовое использование и положение &. Таким образом, & является здесь ссылочным оператором, а не оператором адресации. Чтобы вызвать функцию, просто используйте любое имя.

Идентификатор ссылки — это не то же самое, что идентификатор указателя.

Функция, возвращающая указатель

В следующей программе функция возвращает указатель, который является адресом указанного объекта:

#include <iostream>
using namespace std;

float *fn(float fl, int in)
{
float *fll = &fl;
return fll;
}

int main()
{

float *val = fn(2.5, 6);

cout << *val << \n;

return 0;
}

Выход 2,5

Первый оператор в функции fn () предназначен только для создания объекта-указателя. Обратите внимание на одноразовое использование и положение * в сигнатуре функции. Также обратите внимание, как указатель (адрес) был получен в функции main () другим объектом-указателем.

Функция, возвращающая ссылку

В следующей программе функция возвращает ссылку:

#include <iostream>
using namespace std;

float &fn(float fl, int in)
{
float &frr = fl;
return frr;
}

int main()
{

float &val = fn(2.5, 6);

cout << val << \n;

return 0;
}

Выход 2,5.

Первый оператор в функции fn () предназначен только для создания ссылки. Обратите внимание на одноразовое использование и положение & в сигнатуре функции. Также обратите внимание, как ссылка была получена в функции main () по другой ссылке.

Передача указателя на функцию

В следующей программе указатель, который на самом деле является адресом объекта с плавающей точкой, отправляется в качестве аргумента функции:

#include <iostream>
using namespace std;

float fn(float *fl, int in)
{
return *fl;
}

int main()
{
float v = 2.5;

float val = fn(&v, 6);

cout << val << \n;

return 0;
}

Выход 2,5

Обратите внимание на использование и положение * для параметра с плавающей запятой в сигнатуре функции. Как только начинается вычисление функции fn (), делается следующий оператор:

float *fl = &v;

Оба fl и & v указывают на один и тот же заостренный объект, который содержит 2.5. * fl в операторе возврата не является декларацией; это означает, что значение заостренного объекта, на которое указывает объект-указатель.

Передача ссылки на функцию

В следующей программе ссылка отправляется в качестве аргумента функции:

#include <iostream>
using namespace std;

float fn(float &fl, int in)
{
return fl;
}

int main()
{
float v = 2.5;

float val = fn(v, 6);

cout << val << \n;

return 0;
}

Выход 2,5

Обратите внимание на использование и положение & для параметра float в сигнатуре функции. Как только начинается вычисление функции fn (), делается следующий оператор:

float &fl = v;

Передача массива функции

Следующая программа показывает, как передать массив функции:

#include <iostream>
using namespace std;

int fn(int arra[])
{
return arra[2];
}

int main()
{

int arr[] = {000, 100, 200, 300, 400};

int val = fn(arr);

cout << val << \n;

return 0;
}

Выход 200.

В этой программе передается массив. Обратите внимание, что параметр сигнатуры функции имеет объявление пустого массива. Аргументом в вызове функции является только имя созданного массива.

Может ли функция C ++ вернуть массив?

Функция в C ++ может возвращать значение массива, но не может возвращать массив. Компиляция следующей программы приводит к сообщению об ошибке:

#include <iostream>
using namespace std;

int fn(int arra[])
{
return arra;
}

int main()
{

int arr[] = {000, 100, 200, 300, 400};

int val = fn(arr);

return 0;
}

Указатель указателя

Указатель может указывать на другой указатель. То есть объект-указатель может иметь адрес другого объекта-указателя. Они по-прежнему должны быть одного типа. Следующий фрагмент кода иллюстрирует это:

    int ptdInt = 5;

int *ptrInt = &ptdInt;

int **ptrptrInt = &ptrInt;

cout << **ptrptrInt << \n;

Выход 5.

Читайте также:  Как настроить сообщения журнала в библиотеке запросов Python?

В объявлении указателя на указатель используется двойной *. Чтобы вернуть значение последнего заостренного объекта, по-прежнему используется двойной *.

Массив указателей

Следующая программа показывает, как кодировать массив указателей:

#include <iostream>
using namespace std;

int main()
{
int num0=000, num1=100, num2=200, num3=300, num4=400;
int *no0=&num0, *no1=&num1, *no2=&num2, *no3=&num3, *no4=&num4;

int *arr[] = {no0, no1, no2, no3, no4};

cout << *arr[4] << \n;

return 0;
}

Результат:

400

Обратите внимание на использование и положение * в объявлении массива. Обратите внимание на использование * при возврате значения в массиве. С указателями указателей задействованы два *. В случае массива указателей об одном * уже позаботились, потому что идентификатор массива является указателем.

Массив строк переменной длины

Строковый литерал — это константа, возвращающая указатель. Массив строк переменной длины — это массив указателей. Каждое значение в массиве является указателем. Указатели — это адреса к ячейкам памяти, они имеют одинаковый размер. Строки разной длины находятся в другом месте памяти, а не в массиве. Следующая программа иллюстрирует использование:

#include <iostream>
using namespace std;

int main()
{

const char *arr[] = {«woman», «boy», «girl», «adult»};

cout << arr[2] << \n;

return 0;
}

На выходе получается «girl».

Объявление массива начинается с зарезервированного слова «const» для константы; за которым следует «char» для символа, затем звездочка *, чтобы указать, что каждый элемент является указателем. Чтобы вернуть строку из массива, * не используется из-за неявного характера указателя каждой строки. Если используется *, то будет возвращен первый элемент строки.

Указатель на функцию, возвращающую указатель

Следующая программа показывает, как кодируется указатель на функцию, возвращающую указатель:

#include <iostream>
using namespace std;

int *fn()
{
int num = 4;
int *inter = &num;
return inter;
}

int main()
{

int *(*func)() = &fn;
int val = *func();

cout << val << \n;

return 0;
}

Выход 4.

Объявление указателя на функцию, возвращающую указатель, аналогично объявлению указателя на обычную функцию, но перед ним стоит звездочка. Первый оператор в функции main () иллюстрирует это. Чтобы вызвать функцию с помощью указателя, поставьте перед ней *.

Заключение

Чтобы создать указатель на скаляр, сделайте что-нибудь вроде:

float pointed;
float *pointer = &pointed;

* имеет два значения: в объявлении указывает указатель; чтобы что-то вернуть, это значение указанного объекта.

Имя массива — это постоянный указатель на первый элемент массива.

Чтобы создать указатель на функцию, вы можете:

int (*func)() = &fn;

где fn () — функция, определенная в другом месте, а func — указатель.

& имеет два значения: в объявлении он указывает ссылку (синоним) на тот же объект, что и другой идентификатор; при возврате означает адрес.

Чтобы создать ссылку на функцию, вы можете:

float (&refFunc)(float, int) = fn;

где fn () — функция, определенная в другом месте, а refFunc — ссылка.

Когда функция возвращает указатель, возвращаемое значение должно быть получено указателем. Когда функция возвращает ссылку, возвращаемое значение должно быть получено по ссылке.

При передаче указателя на функцию параметр является объявлением, а аргумент — адресом указанного объекта. При передаче ссылки на функцию параметр является объявлением, а аргумент — ссылкой.

При передаче массива функции параметр — это объявление, а аргумент — это имя массива без []. Функция C ++ не возвращает массив.

Для указателя на указатель требуется два * вместо одного, где это необходимо.

Оцените статью
bestprogrammer.ru
Добавить комментарий