Указатели и ссылки в C++. Шпаргалка. Часть 1.

Иногда нужно быстро вспомнить как работать с указателями и ссылками в C++. Написал для себя пример кода-шпаргалку. Компилировал в MS Visual Studio 2017.

#include "pch.h"
#include <iostream>
#include <string> 
#include <vector>

void sum(int a, int b)
{
	b = a + b;
	printf("Результат внутри функции sum(100, var), var = %i\r\n", b);
}

void sumptr(int a, int* b)
{
	*b = a + *b;
	printf("Результат внутри функции sumptr(100, &var), var = %i\r\n", *b);
}

float sum(float x, float y)
{
	return x + y;
}

float sub(float x, float y)
{
	return x - y;
}

class One
{
public:
	std::string Tag;
	One() {}
};

class Two
{
public:
	One* one;
	std::string Tag;
	int id;
	void Check(int id, One* one)
	{
		this->id = id;
		std::cout << "Id: " + std::to_string(this->id) + " " + one->Tag + "\r\n";
	};
	Two() {}
};

typedef std::vector<Two*> Twos;

class Three
{
public:
	void* one; //One
	std::string Tag;
	Twos twos;
	Three() {}
};

typedef std::vector<Three*> Threes;

int main()
{
	setlocale(LC_ALL, "Rus");

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

int var; //Переменная типа int
	int* ptrvar;
	ptrvar = NULL; // Указатель на переменную типа int. Лучше инициализировать NULL, поскольку изначально указатель указывает на случайную область памяти.
	printf("Адрес переменной ptrvar = %p (указатель инициализирован NULL)\r\n", ptrvar);

	var = 100;
	ptrvar = &var; //Сохраняем значение адреса переменной в указателе 

	printf("Значение переменной var = %i\r\n", var);
	printf("Значение по указателю *ptrvar = %i\r\n\r\n", *ptrvar);
	printf("Адрес переменной &var = %p\r\n", &var);
	printf("Адрес переменной &var = %X\r\n", &var);
	if (ptrvar)
	{
		printf("Адрес переменной ptrvar = %p\r\n", ptrvar);
	}
	else
	{
		printf("Указатель не определен\r\n");
	}

	float value = 100.65;
	//int *ptrvar = &value; //Если раскомментировать, то будет ошибка, поскольку float не может быть размещен в указателе ссылающемся на переменную типа int

Адрес переменной ptrvar = 00000000 (указатель инициализирован NULL)
Значение переменной var = 100
Значение по указателю *ptrvar = 100
Адрес переменной &var = 00F5FAF4
Адрес переменной &var = F5FAF4
Адрес переменной ptrvar = 00F5FAF4

Указатель на любой тип данных void* в C++

	printf("\r\n--------------Указатель на любой тип данных void*---------------------\r\n");
	void *ptrvoid; //Указатель на любой тип данных

	ptrvoid = &var;
	int* ptrvar1 = static_cast<int*>(ptrvoid); //Можно привести к нужному типу так
	printf("Адрес переменной var = %p, значение переменной var = %i\r\n", ptrvar1, *ptrvar1);
	ptrvoid = &value;
	float* ptrvar2 = (float*)ptrvoid; //Можно привести к нужному типу и так
	printf("Адрес переменной var = %p, значение переменной var = %f\r\n", ptrvar1, *ptrvar2);

—————Указатель на любой тип данных void*———————
Адрес переменной var = 00F5FAF4, значение переменной var = 100
Адрес переменной var = 00F5FAF4, значение переменной var = 100,650002

Указатель в аргументах функции
в C++

printf("\r\n--------------Указатель в аргументах функции--------------------------\r\n");
	sum(100, var);
	printf("Результат sum(100, var) вне функции, var = %i\r\n\r\n", var);

	sumptr(100, &var);
	printf("Результат sumptr(100, &var) вне функции, var = %i\r\n", var);

—————Указатель в аргументах функции—————————
Результат внутри функции sum(100, var), var = 200
Результат sum(100, var) вне функции, var = 100
Результат внутри функции sumptr(100, &var), var = 200
Результат sumptr(100, &var) вне функции, var = 200

Указатель на функцию
в C++

printf("\r\n--------------Указатель на функцию--------------------------\r\n");
void(*ptrsum)(int, int*) = sumptr; //Указатель обязательно должен быть в скобках. Если void *message (void); - будет прототип функции message, возвращающей тип void. 
	ptrsum(100, &var); //Используем ссылку на функцию
	printf("Результат ptrrf(100, &var) вне функции, var = %i\r\n", var);

—————Указатель на функцию—————————
Результат внутри функции sumptr(100, &var), var = 300
Результат ptrrf(100, &var) вне функции, var = 300

Массив указателей на функции
в C++

printf("\r\n--------------Массив указателей на функции--------------------------\r\n");
	float(*ops[2])(float, float) = { sum, sub };
	float a = sizeof(ops);
	float b = sizeof(float);
	float c = sizeof(ops[0]);
	int len = a / b;
	printf("Sizeof(ops) = %i, sizeof(float) = %i, sizeof(ops[0]) = %i, len = %i\r\n", (int)a, (int)b, (int)c, len);
	for (int i = 0; i < len; i++)
	{
		printf("Результат ops[%i](a, b) = %f\r\n", i, ops[i](a, b));
	}

—————Массив указателей на функции—————————
Sizeof(ops) = 8, sizeof(float) = 4, sizeof(ops[0]) = 4, len = 2
Результат ops[0](a, b) = 12,000000
Результат ops[1](a, b) = 4,000000

Ссылка на переменную
в C++

printf("\r\n--------------Ссылки---------------------------------------------------\r\n");
	int &pvar = var; // Объявляем ссылку на переменную var. Теперь p это псевдоним pvar
	printf("Адрес переменной var = %p, значение var = %i\r\n", &var, var);
	printf("Адрес ссылки var = %p, значение pvar = %i\r\n", &pvar, pvar);

—————Ссылки—————————————————
Адрес переменной var = 00F5FAF4, значение var = 300
Адрес ссылки var = 00F5FAF4, значение pvar = 300

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

	printf("\r\n--------------Ссылка на функцию---------------------------------------\r\n");
	void(&rf)(int, int*) = sumptr;
	rf(100, &var); //Используем ссылку на функцию
	printf("Результат rf(100, &var) вне функции, var = %i\r\n", var);

—————Ссылка на функцию—————————————
Результат внутри функции sumptr(100, &var), var = 400
Результат rf(100, &var) вне функции, var = 400

Резервирование памяти под переменную вручную
в C++

printf("\r\n--------------Резервирование памяти под переменную вручную------------\r\n");
	int *ptrint = new int; //Вручную зарезервировали область памяти под переменную типа int
	printf("Адрес переменной ptr = %p\r\n", ptrint);
	*ptrint = 100.65; //Помещаем значение не соответствующее типу int
	printf("Значение переменной ptrint = %i\r\n", *ptrint);
	printf("Значение переменной ptrint = %f\r\n", *ptrint);  //Из-за несоответствия выведет неверную информацию 
	*ptrint = 100;
	(*ptrint)++; //Инкремент переменной 
	printf("Значение inc переменной ptrint = %i\r\n", *ptrint);
	delete ptrint; //Удаление вручную зарезервированной области памяти. 

	float *ptrfloat = new float; //Вручную зарезервировали область памяти под переменную типа float
	*ptrfloat = 100.65;
	printf("Значение переменной ptr = %f\r\n", *ptrfloat);
	delete ptrfloat;

—————Резервирование памяти под переменную вручную————
Адрес переменной ptr = 010EE888
Значение переменной ptrint = 100
Значение переменной ptrint = 0,000000
Значение inc переменной ptrint = 101
Значение переменной ptr = 100,650002

Динамическое создание одномерного массива
в C++

	printf("\r\n--------------Динамическое создание одномерного массива----------------\r\n");
	int size = 3;
	int *ptrarr = new int[size]; //Динамически задаем размер массива
	for (int i = 0; i < 3; i++)
	{
		*(ptrarr + i) = 9 - i;  //Помещаем элемент в массив через указатель
		printf("Array address (ptrarr + %i) = %p, *(ptrarr + %i) = %i, ptrarr[%i] = %i\r\n", i, (ptrarr + i), i, *(ptrarr + i), i, ptrarr[i]);
		ptrarr[i] = i; //Помещаем элемент в массив обычным способом
		printf("Array address &ptrarr[%i] = %p, ptrarr[%i] = %i\r\n\r\n", i, &ptrarr[i], i, ptrarr[i]);
	}
	delete[]ptrarr;

—————Динамическое создание одномерного массива—————-
Array address (ptrarr + 0) = 010EF6E0, *(ptrarr + 0) = 9, ptrarr[0] = 9
Array address &ptrarr[0] = 010EF6E0, ptrarr[0] = 0
Array address (ptrarr + 1) = 010EF6E4, *(ptrarr + 1) = 8, ptrarr[1] = 8
Array address &ptrarr[1] = 010EF6E4, ptrarr[1] = 1
Array address (ptrarr + 2) = 010EF6E8, *(ptrarr + 2) = 7, ptrarr[2] = 7
Array address &ptrarr[2] = 010EF6E8, ptrarr[2] = 2

Динамическое создание двумерного массива
в C++

printf("\r\n--------------Динамическое создание двумерного массива-----------------\r\n");
	const int size1 = 2;
	const int size2 = 3;
	// двумерный массив размером 2x3
	int** i_arr = new int*[size1];
	for (int i = 0; i < size1; i++) {
		int *ptrint = new int[size2]; //Создаем указатель на двумерный массив
		i_arr[i] = ptrint; // new int[size2]; //Заполняем каждую строку одномерного массива указателей размером size1 указателями на одномерный массив указателей размером size2 
		printf("В i_arr[%i] = %X, ptrint = %p\r\n", i, i_arr[i], ptrint);
		for (int j = 0; j < size2; j++)
		{
			i_arr[i][j] = i + 10 * j;
		}
		printf("i_arr[%i][0] = %i, i_arr[%i][1] = %i, i_arr[%i][2] = %i\r\n", i, i_arr[i][0], i, i_arr[i][1], i, i_arr[i][2]);
		for (int j = 0; j < size2; j++)
		{
			*(ptrint + j) = i + 10 * j;
		}
		*(i_arr + i) = ptrint;
		printf("i_arr[%i][0] = %i, i_arr[%i][1] = %i, i_arr[%i][2] = %i\r\n", i, i_arr[i][0], i, i_arr[i][1], i, i_arr[i][2]);
	}
	delete(i_arr);

—————Динамическое создание двумерного массива——————
В i_arr[0] = 10EF558, ptrint = 010EF558
i_arr[0][0] = 0, i_arr[0][1] = 10, i_arr[0][2] = 20
i_arr[0][0] = 0, i_arr[0][1] = 10, i_arr[0][2] = 20
В i_arr[1] = 10EF130, ptrint = 010EF130
i_arr[1][0] = 1, i_arr[1][1] = 11, i_arr[1][2] = 21
i_arr[1][0] = 1, i_arr[1][1] = 11, i_arr[1][2] = 21

Шаблон vector
в C++

printf("\r\n--------------Шаблон vector-----------------\r\n");
	Threes threes;
	for (int i = 0; i &lt; 3; i++)
	{
		Three* three = new Three();
		three->Tag = "Three tag " + std::to_string(i);
		One* one = new One();
		one->Tag = "One tag " + std::to_string(i);
		three->one = one;
		Twos twos;
		for (int i = 0; i &lt; 2; i++)
		{
			Two* two = new Two();
			two->Tag = "Two tag " + std::to_string(i);
			two->Check(i, one);
			twos.push_back(two);
		}
		three->twos = twos;
	    threes.push_back(three);
	}

	for (Three* three : threes)
	{
		std::cout &lt;&lt; three->Tag + "\r\n";
		std::cout &lt;&lt; ((One*)three->one)->Tag + "\r\n";
		for (Two* two : three->twos)
		{
			std::cout &lt;&lt; "\t" + two->Tag + "\r\n";
		}
	}
}

—————Шаблон vector——————
Id: 0 One tag 0
Id: 1 One tag 0
Id: 0 One tag 1
Id: 1 One tag 1
Id: 0 One tag 2
Id: 1 One tag 2
Three tag 0
One tag 0
Two tag 0
Two tag 1
Three tag 1
One tag 1
Two tag 0
Two tag 1
Three tag 2
One tag 2
Two tag 0
Two tag 1

Spread the love
Запись опубликована в рубрике IT рецепты. Добавьте в закладки постоянную ссылку.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *