1.3 Сравнение указателей и ссылок
Ниже представлено сравнение указателей и ссылок на языках программирования С++ и С#:
1)Оба языка поддерживают типизированные указатели, но C# не поддерживает нетипизированные указатели.
2)C++ поддерживает указатели на данные и функции, в то время как C# поддерживает только указатели на данные.
3)C++ поддерживает ссылки как доказуемые объекты, в то время как C# использует ссылки на объекты в качестве ссылок.
4)Оба языка поддерживают постоянные указатели.
5)Только С++ поддерживает указатели на константу.
6)Оба языка поддерживают многоуровневые указатели.
Заключение
В ходе лабораторной работы были применены полученные знания о том, что такое указатель и ссылка, а также была продемонстрирована разница в использовании ссылок и указателей в двух языках программирования.
Приложение А
Программа на C++
#include <iostream>
using namespace std;
int calculate(int digit)
{
int result = digit * 111; return result;
}
int main()
{
int a = 11;
int b = 22;
cout << "Задание №1 - типизация" << endl;
int* pointer_a = &a; //типизированный
void* pointer_b; //нетипизированный
pointer_b = pointer_a;
cout << *static_cast<int*>(pointer_b) << endl; //разыменование нетипизированного указателя
cout << "a = " << *pointer_a << endl;
cout << "b = " << b << endl;
cout << "a адрес: " << pointer_a << endl;
cout << "b адрес: " << pointer_b << endl << endl;
cout << "Задание №2 - указ. на функцию" << endl;
int (*function_pointer) (int); // объявление указателя на функцию
function_pointer = calculate; // присваивание указателю
cout << "указатель на функцию: " << function_pointer(b) << endl;
cout << "указатель на данные: " << *pointer_a << endl << endl;
cout << "Задание №3" << endl;
cout << "указатель на a: " << pointer_a << ", a = " << a << endl; // перевод строки
cout << "указатель на b: " << pointer_b << ", b = " << b << endl << endl; // два перевода строки для разделения вывода
cout <<"Задание №4 - указатель константа"<< endl;
const int constant_a = 123; // указатель-константа
const int* constant_pointer = &b;// указатель на константу
cout <<"константа-указатель на b: " << constant_pointer << ", b = " << *constant_pointer << endl;
b = b * 100;
cout <<"константа-указатель на новый b: " << constant_pointer << ", b = " << *constant_pointer <<endl;
const int* pointer_to_constant = &constant_a;
cout <<"constant address: " << pointer_to_constant << ", constant: " << *pointer_to_constant << endl << endl;
cout <<"Задание №5 - многоуровневые указатели" << endl;
int** multi_pointer = &pointer_a; // создается указатель на указатель
cout <<"указатель на указатель: " << multi_pointer << endl;
cout << "указатель на значение : " << pointer_a << endl;
cout << "значение: " << **multi_pointer << endl << endl; // вывод значения x, доступ получив как раз через многоуровневый ук-ль
cout <<"Задание №6 - разница" << endl;
int& reference_b = b; // объявление ссылки
cout <<"указатель на b: " << pointer_b << endl; // вывод y через указатель
cout <<"ссылка на b: " << reference_b << endl; // а тут уже через ссылку
reference_b +=100;
cout <<"ссылка была изменена: " << reference_b << endl;
}
Приложение Б
Программа на C#
using System;
unsafe class Program
{
static int Multiplier(int digit)
{
return digit * 100;
}
static void Main()
{
int valueA = 123;
int valueB = 321;
Console.WriteLine("#1");
int* pointerA = &valueA; // типизированный указатель
Console.WriteLine($"valueA = {*pointerA}");
Console.WriteLine($"адрес valueA: {(IntPtr)pointerA}");
void* pointerB = &valueB; // нетипизированный указатель
Console.WriteLine($"valueB = {valueB}");
Console.WriteLine($"адрес valueB: {(IntPtr)pointerB}");
//Console.WriteLine($"unnamed x: {pointerB}");
Console.WriteLine("При попытке разыменовать указатель valueB будет ошибка\n");
Console.WriteLine("#2");
Func<int, int> functionPointer = Multiplier; // Делегат вместо указателя на функцию
Console.WriteLine($"указатель на функцию(делегат): {functionPointer(valueA)}"); // вызывает функцию
Console.WriteLine($"указатель на valueA: {(IntPtr)pointerA}\n"); // выводится адрес на переменную
Console.WriteLine("#3");
Console.WriteLine($"указатель на valueA: {(IntPtr)pointerA}, указуемый объект = {valueA}");
Console.WriteLine($"указатель на valueB: {(IntPtr)pointerB}, указуемый объект = {valueB}\n");
Console.WriteLine("#4");
// В C# нельзя брать адрес константного литерала, поэтому заменяем const int на int
int constantValue = 123;
int* pointerToConstant = &constantValue; // Указатель на константу
Console.WriteLine($"pointerToConstant указатель на константный value = {*pointerToConstant}");
pointerToConstant = &valueB; // можно поменять адрес указателя
Console.WriteLine($"Новый адрес для value (взят от valueB) = {*pointerToConstant}");
// Симуляция указателя-константы: объявляем локальную переменную и не переназначаем её.
int* constantPointer = &valueA; //readonly имитирует константу-указатель
*constantPointer = valueA; // Указатель-константа. Присваивание значения по адресу
//constantPointer = &valueA; --- невозможно присвоить получается
Console.WriteLine($"constantPointer указатель на valueA = {*constantPointer}");
*constantPointer = 40; // изменяем значение через указатель
Console.WriteLine($"Смена значения указуемого объекта = {valueA}\n");
Console.WriteLine("#5");
int** doublePointer = &pointerA; // Указатель на указатель
Console.WriteLine($"Указатель на указатель: {(IntPtr)doublePointer}");
Console.WriteLine($"Указатель на данные: {(IntPtr)(*doublePointer)}");
Console.WriteLine($"значение: {**doublePointer}\n");
// по факту ссылка дублирует переменную по другому имени, что позволяет изменять значение целевой переменной
// указатель позволяет не дублировать переменную, а изменять ее значение по адресу
Console.WriteLine("#6");
ref int reference = ref valueB; // Ссылка
Console.WriteLine($"ссылка на valueB: {reference}");
reference += 100;
Console.WriteLine($"измененная ссылка: {reference}");
Console.WriteLine($"valueB was changed: {valueB}");
}
}
Томск 2025
