C++ Указатели с примерами

Что такое указатели?

In C++, указатель относится к переменной, которая содержит адрес другой переменной. Как и обычные переменные, указатели имеют тип данных. Например, указатель целочисленного типа может содержать адрес переменной целочисленного типа. Указатель символьного типа может содержать адрес переменной символьного типа.

Вы должны увидеть указатель как символическое представление адреса памяти. С помощью указателей программы могут имитировать вызов по ссылке. Они также могут создавать динамические структуры данных и манипулировать ими. В C++, переменная-указатель относится к переменной, указывающей на определенный адрес в памяти, на который указывает другая переменная.

Адреса в C++

Чтобы понять C++ указатели, вы должны понимать, как компьютеры хранят данные.

Когда вы создаете переменную в своем C++ программе, ей отводится некоторое пространство в памяти компьютера. Значение этой переменной сохраняется в назначенном месте.

Чтобы узнать место в памяти компьютера, где хранятся данные, C++ обеспечивает & (ссылочный) оператор. Оператор возвращает адрес, который занимает переменная.

Например, если x — переменная, &x возвращает адрес переменной.

Синтаксис объявления указателя

Декларация C++ имеет следующий синтаксис:

datatype *variable_name; 
  • Тип данных — это базовый тип указателя, который должен быть допустимым. C++ тип данных.
  • Имя_переменной должно быть именем переменной-указателя.
  • Звездочка, использованная выше для объявления указателя, аналогична звездочке, используемой для выполнения операции умножения. Это звездочка, которая помечает переменную как указатель.

Вот пример допустимых объявлений указателей в C++:

int    *x;    // a pointer to integer
double *x;    // a pointer to double
float  *x;    // a pointer to float
char   *ch     // a pointer to a character

Оператор ссылки (&) и оператор уважения (*)

Оператор ссылки (&) возвращает адрес переменной.

Оператор разыменования (*) помогает нам получить значение, сохраненное по адресу памяти.

Например:

Если у нас есть переменная с именем num, хранящаяся по адресу 0x234 и хранящая значение 28.

Ссылочный оператор (&) вернет 0x234.

Оператор разыменования (*) вернет 5.

Пример 1:

#include <iostream>
using namespace std;
int main() {
	int  x = 27;  
	int  *ip;        
	ip = &x;       
	cout << "Value of x is : ";
	cout << x << endl;
	cout << "Value of ip is : ";
	cout << ip<< endl;
	cout << "Value of *ip is : ";
	cout << *ip << endl;
	return 0;
}

Вывод:

Оператор ссылки (&) и оператор уважения (*)

Как это работает:

Оператор ссылки (&) и оператор уважения (*)

Вот скриншот кода:

Оператор ссылки (&) и оператор уважения (*)

Пояснение к коду:

  1. Импортируйте файл заголовка iostream. Это позволит нам использовать функции, определенные в заголовочном файле, без ошибок.
  2. Включите пространство имен std, чтобы использовать его классы без его вызова.
  3. Вызовите функцию main(). Логику программы следует добавить в тело этой функции. { отмечает начало тела функции.
  4. Объявите целочисленную переменную x и присвойте ей значение 27.
  5. Объявите переменную-указатель *ip.
  6. Сохраните адрес переменной x в переменной-указателе.
  7. Напечатайте текст на консоли.
  8. Выведите значение переменной x на экран.
  9. Напечатайте текст на консоли.
  10. Выведите адрес переменной x. Значение адреса сохранялось в переменной ip.
  11. Напечатайте текст на консоли.
  12. Выведите значение, хранящееся по адресу указателя.
  13. Программа должна возвращать значение после успешного выполнения.
  14. Конец тела функции main().

Указатели и массивы

Массивы и указатели работают на основе схожей концепции. При работе с массивами, имеющими указатели, следует учитывать разные вещи. Само имя массива обозначает базовый адрес массива. Это означает, что для присвоения адреса массива указателю не следует использовать амперсанд (&).

Например:

p = arr;

Вышеупомянутое верно, поскольку arr представляет адрес массива. Вот еще один пример:

p = &arr;

Вышеупомянутое неверно.

Мы можем неявно преобразовать массив в указатель. Например:

int arr [20];
int * ip;

Ниже приведена допустимая операция:

ip = arr;

После приведенного выше объявления ip и arr будут эквивалентны и будут иметь общие свойства. Однако ip можно назначить другой адрес, но мы не можем ничего назначить arr.

Пример 2:

В этом примере показано, как перемещаться по массиву с помощью указателей:

#include <iostream>
using namespace std;
int main() {
	int *ip;
	int arr[] = { 10, 34, 13, 76, 5, 46 };
	ip = arr;
	for (int x = 0; x < 6; x++) {
		cout << *ip << endl;
		ip++;
	}
	return 0;
}

Вывод:

Указатели и массивы

Вот скриншот кода:

Указатели и массивы

Пояснение к коду:

  1. Объявите целочисленную переменную-указатель ip.
  2. Объявите массив с именем arr и сохраните в нем 6 целых чисел.
  3. Назначьте arr IP. IP и arr станут эквивалентными.
  4. Создайте цикл for. Переменная цикла x была создана для перебора элементов массива с индексом от 0 до 5.
  5. Выведите значения, хранящиеся по адресу IP указателя. На каждую итерацию будет возвращено одно значение, всего будет выполнено 6 повторений. Конец - это C++ ключевое слово, которое означает конечную строку. Это действие позволяет переместить курсор на следующую строку после печати каждого значения. Каждое значение будет напечатано в отдельной строке.
  6. Чтобы переместить указатель на следующую позицию int после каждой итерации.
  7. Конец цикла for.
  8. Программа должна что-то вернуть при успешном выполнении.
  9. Конец тела функции main().

НУЛЕВОЙ указатель

Если нет точного адреса, который должен быть назначен, то переменной-указателю может быть присвоено значение NULL. Это следует сделать во время декларации. Такой указатель называется нулевым указателем. Его значение равно нулю и определено во многих стандартных библиотеках, таких как iostream.

Пример 3:

#include <iostream>
using namespace std;
int main() {
	int  *ip = NULL;
	cout << "Value of ip is: " << ip;
	return 0;
}

Вывод:

НУЛЕВОЙ указатель

Вот скриншот кода:

НУЛЕВОЙ указатель

Пояснение к коду:

  1. Объявите переменную-указатель ip и присвойте ей значение NULL.
  2. Выведите значение переменной-указателя ip вместе с текстом на консоли.
  3. Программа должна вернуть значение после успешного завершения.
  4. Конец тела функции main().

Указатели переменных

В C++, вы можете манипулировать данными непосредственно из памяти компьютера.

Пространство памяти может быть назначено или переназначено по желанию. Это стало возможным благодаря переменным указателя.

Переменные-указатели указывают на определенный адрес в памяти компьютера, на который указывает другая переменная.

Его можно объявить следующим образом:

int *p;

Или,

int* p;

В вашем примере мы объявили переменную-указатель p.

Он будет содержать адрес памяти.

Звездочка — это оператор разыменования, который означает указатель на.

Указатель p указывает на целое значение в адресе памяти.

Пример 4:

#include <iostream>

using namespace std;
int main() {
	int *p, x = 30;
	p = &x;
	cout << "Value of x is: " << *p;
	return 0;
}

Вывод:

Указатели переменных

Вот скриншот кода:

Указатели переменных

Пояснение к коду:

  1. Объявите переменную-указатель p и переменную x со значением 30.
  2. Присвойте адрес переменной x переменной p.
  3. Выведите значение переменной-указателя p вместе с текстом на консоли.
  4. Программа должна вернуть значение после успешного завершения.
  5. Конец тела функции main().

Применение указателей

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

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

Пример 5:

#include <iostream>

using namespace std;
void test(int*, int*);
int main() {
	int a = 5, b = 5;
	cout << "Before changing:" << endl;
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	test(&a, &b);

	cout << "\nAfter changing" << endl;
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	return 0;
}

void test(int* n1, int* n2) {
	*n1 = 10;
	*n2 = 11;
}

Вывод:

Применение указателей

Вот скриншот кода:

Применение указателей

Пояснение к коду:

  1. Создайте прототип функции с именем test, которая будет принимать два целочисленных параметра.
  2. Вызовите функцию main(). Мы добавим логику программы внутрь ее тела.
  3. Объявите две целочисленные переменные a и b, каждая со значением 5.
  4. Напечатайте текст на консоли. Endl (конечная строка) переместит курсор, чтобы начать печать на следующей строке.
  5. Выведите значение переменной a на консоль вместе с другим текстом. Endl (конечная строка) переместит курсор, чтобы начать печать на следующей строке.
  6. Выведите значение переменной b на консоль вместе с другим текстом. Endl (конечная строка) переместит курсор, чтобы начать печать на следующей строке.
  7. Создайте функцию с именем test(), которая принимает в качестве параметров адреса переменных a и b.
  8. Напечатайте текст на консоли. \n создаст новую пустую строку перед печатью текста. Endl (конечная строка) переместит курсор, чтобы начать печать на следующей строке после печати текста.
  9. Выведите значение переменной a на консоль вместе с другим текстом. Endl (конечная строка) переместит курсор, чтобы начать печать на следующей строке.
  10. Выведите значение переменной b на консоль вместе с другим текстом. Endl (конечная строка) переместит курсор, чтобы начать печать на следующей строке.
  11. Программа должна вернуть значение после успешного завершения.
  12. Конец тела функции main().
  13. Определение функции test(). Функция должна принимать две целочисленные переменные указателя *n1 и *n2.
  14. Присвоение переменной указателя *n1 значения 10.
  15. Присвоение переменной указателя *n2 значения 11.
  16. Конец тела функции test().

Несмотря на то, что переменным a и b внутри функционального теста присваиваются новые значения, после завершения вызова функции это не отражается на внешней функции main.

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

В приведенном выше случае функция «test» имеет адрес переменных «a» и «b». Эти две переменные доступны напрямую из функции «test», и, следовательно, любые изменения, внесенные в эти переменные, отражаются в вызывающей функции «main».

Преимущества использования указателей

Вот плюсы/преимущества использования указателей.

  • Указатели — это переменные, в которых хранятся адреса других переменные в C++.
  • Функция может изменять и возвращать более одной переменной с помощью указателей.
  • Память может быть динамически выделена и освобождена с помощью указателей.
  • Указатели помогают упростить программу.
  • Скорость выполнения программы увеличивается за счет использования указателей.

Итого

  • Указатель относится к переменной, содержащей адрес другой переменной.
  • Каждый указатель имеет допустимый тип данных.
  • Указатель — это символическое представление адреса памяти.
  • Указатели позволяют программам имитировать вызов по ссылке, а также создавать и манипулировать динамическими структурами данных.
  • Массивы и указатели используют связанную концепцию.
  • Имя массива обозначает базу массива.
  • Если вы хотите присвоить адрес массива указателю, не используйте амперсанд (&).
  • Если нет конкретного адреса для назначения переменной-указателя, присвойте ей значение NULL.