Иногда нужно быстро вспомнить как работать с указателями и ссылками в 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 < 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 < 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 << three->Tag + "\r\n"; std::cout << ((One*)three->one)->Tag + "\r\n"; for (Two* two : three->twos) { std::cout << "\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