initial commit

This commit is contained in:
nihonium 2022-09-01 16:37:41 +03:00
commit 2369f801af
Signed by: nihonium
GPG key ID: 0251623741027CFC
76 changed files with 4273 additions and 0 deletions

53
.gitignore vendored Normal file
View file

@ -0,0 +1,53 @@
# ---> C
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf

View file

@ -0,0 +1,180 @@
\documentclass{article}
\usepackage[utf8x]{inputenc}
\usepackage{ucs}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{marvosym}
\usepackage{wasysym}
\usepackage{upgreek}
\usepackage[english,russian]{babel}
\usepackage{graphicx}
\usepackage{float}
\usepackage{textcomp}
\usepackage{hyperref}
\usepackage{geometry}
\geometry{left=2cm}
\geometry{right=1.5cm}
\geometry{top=1cm}
\geometry{bottom=2cm}
\usepackage{tikz}
\usepackage{ccaption}
\usepackage{multicol}
\usepackage{fancyvrb}
\usepackage{listings}
%\setlength{\columnsep}{1.5cm}
%\setlength{\columnseprule}{0.2pt}
\usepackage{colortbl,graphicx,tikz}
\definecolor{X}{rgb}{.5,.5,.5}
\title{ДЗ. Работа с изображениями в формате \texttt{.ppm}}
\date{}
\begin{document}
\pagenumbering{gobble}
\lstset{
language=C++, % choose the language of the code
basicstyle=\linespread{1.1}\ttfamily,
columns=fixed,
fontadjust=true,
basewidth=0.5em,
keywordstyle=\color{blue}\bfseries,
commentstyle=\color{gray},
stringstyle=\ttfamily\color{orange!50!black},
showstringspaces=false,
%numbers=false, % where to put the line-numbers
numbersep=5pt,
numberstyle=\tiny\color{black},
numberfirstline=true,
stepnumber=1, % the step between two line-numbers.
numbersep=10pt, % how far the line-numbers are from the code
backgroundcolor=\color{white}, % choose the background color. You must add \usepackage{color}
showstringspaces=false, % underline spaces within strings
captionpos=b, % sets the caption-position to bottom
breaklines=true, % sets automatic line breaking
breakatwhitespace=true, % sets if automatic breaks should only happen at whitespace
xleftmargin=.2in,
extendedchars=\true,
keepspaces = true,
}
\lstset{literate=%
*{0}{{{\color{red!20!violet}0}}}1
{1}{{{\color{red!20!violet}1}}}1
{2}{{{\color{red!20!violet}2}}}1
{3}{{{\color{red!20!violet}3}}}1
{4}{{{\color{red!20!violet}4}}}1
{5}{{{\color{red!20!violet}5}}}1
{6}{{{\color{red!20!violet}6}}}1
{7}{{{\color{red!20!violet}7}}}1
{8}{{{\color{red!20!violet}8}}}1
{9}{{{\color{red!20!violet}9}}}1
}
\title{Семинар \#1: Введение в язык C++ (для тех, кто знает C). Классные задачи.\vspace{-5ex}}\date{}\maketitle
\section*{Hello world++}
Пишем первую программу на \texttt{C++}
\begin{lstlisting}
#include <cstdio>
int main() {
printf("Hello World++\n");
}
\end{lstlisting}
Все библиотеки из языка \texttt{C} можно использовать и в языке \texttt{C++}. Только название библиотеки без \texttt{.h} на конце и с символом \texttt{c} в начале:
\begin{verbatim}
<stdio.h> -------> <cstdio>
\end{verbatim}
Для компиляции используйте компилятор \texttt{g++}. Вот так:
\begin{verbatim}
g++ helloworld.cpp
./a.out
\end{verbatim}
Или, если вы хотите установить у исполняемого файла своё имя за место \texttt{a.out}:
\begin{verbatim}
g++ -o hello helloworld.cpp
./hello
\end{verbatim}
\begin{itemize}
\item \textbf{Задача 1:} Скомпилируйте и запустите простейшую программу \texttt{00helloworld.cpp}.
\item \textbf{Задача 2:} Разберитесь в программе \texttt{01structnaming.cpp}. Скомпилируйте и запустите.
\end{itemize}
\section*{Тип bool}
В прошлом семестре, для хранения результатов логических операций, мы использовали целочисленные типы.\\
В языке \texttt{C++} есть встроенный тип \texttt{bool}, который может принимать 2 значения (\texttt{true} и \texttt{false}).
\begin{lstlisting}
#include <cstdio>
int main() {
bool a = true;
bool b = false;
bool c = a || b;
if (c)
printf("Yes\n");
else
printf("No\n");
}
\end{lstlisting}
\begin{itemize}
\item \textbf{Задача 3:} Что напечатает эта программа? Скомпилируйте её и запустите (\texttt{02bool.cpp})
\item \textbf{Задача 4:} Напишите функцию, которая будет принимать на вход целое число и возвращать \texttt{true}, если число оканчивается на \texttt{0} и \texttt{false} иначе. Вызовите эту функцию из \texttt{main}.
\end{itemize}
\newpage
\section*{Пространство имён}
\begin{lstlisting}
#include <cstdio>
// Определяем переменные, структуры, функции внутри пространства имён foo
namespace foo {
int a = 5;
int square(int x) {
return x * x;
}
}
// Чтобы получить доступ к ним вне пространства имён, нужно добавить к именам foo::
int main() {
printf("%d\n", foo::a);
}
\end{lstlisting}
\begin{itemize}
\item \textbf{Задача 5:} Возведите \texttt{foo::a} в квадрат с помощью функции \texttt{foo::square}.
\item \textbf{Задача 6:} Создайте своё пространство имён по имени \texttt{bar} и определите в нём переменную \texttt{a = 7}. Напечатайте значение этой переменной в \texttt{main}.
\item \textbf{Задача 7:} Сделайте задание в программе \texttt{03namespace.cpp}.
\end{itemize}
\section*{Ссылки}
Ссылка -- это переменная, которая является новым именем для существующего участка памяти.
\begin{lstlisting}
#include <cstdio>
int main() {
int a = 10;
// Создадим ссылку r на переменную a
int& r = a;
// Теперь, если изменить r, то поменяется и a
r += 5;
printf("%d\n", a);
}
\end{lstlisting}
Ссылки часто используются для тех же целей, что и указатели (только со ссылкам работать удобнее).
В отличии от указателей, ссылки:
\begin{enumerate}
\item Должны всегда инициализироваться при создании
\item Не могут никуда не ссылаться (т.е. не могут равняться \texttt{NULL})
\item Их нельзя переприсвоить. При использовании оператора \texttt{=} со ссылками изменяется та переменная, на которую ссылка ссылается, а не сама ссылка.
\end{enumerate}
\begin{itemize}
\item \textbf{Задача 8:} Сделайте задание в файлах \texttt{04ref.cpp}, \texttt{05ref.cpp} и \texttt{06ref.cpp}.
\end{itemize}
\section*{Перегрузка функций}
\begin{itemize}
\item \textbf{Задача 9:} Сделайте задание в файлах \texttt{07function\_overload.cpp}, \texttt{08nulptr.cpp} и \texttt{09default\_arguments.cpp}.
\end{itemize}
\section*{Перегрузка операторов}
\begin{itemize}
\item \textbf{Задача 10:} Сделайте задание в файлах \texttt{10operator\_overload.cpp}, \texttt{11iostream.cpp} и \texttt{12iostream\_overload.cpp}.
\end{itemize}
\end{document}

View file

@ -0,0 +1,33 @@
#include <stdio.h>
/*
Здравствуйте, это первый файл семестра по языку C++ (для тех, кто знаком с языком C)
Язык C++ создан на основе языка C и одним из приоритетов C++ является обратная совместимость с C
Поэтому почти любая программа на языке C будет работать и на языке C++
Однако, нужно помнить, что это разные языки. В C++ было добавлено огромное количество новых возможностей,
что сделало C++ возможно самым объёмным и мощным языком программирования.
C++ содержит в себе во много раз больше всего, чем язык C и пройти его за один семестр не представляется возможным,
но мы пройдём ключевые части этого языка.
Для компиляции программ на C++ будем использовать компилятор g++.
Скомпилируйте эту программу вот так:
g++ 00hello.cpp
И запустите вот так (для Windows):
a.exe
И запустите вот так (для Linux):
./a.out
*/
int main()
{
printf("Hello World of C++\n");
}

View file

@ -0,0 +1,48 @@
#include <stdio.h>
/*
Пространства имён - namespace
Определяем переменные/структуры/функции внутри пространства имён.
Давайте назовём его mipt
Чтобы получить доступ к этим переменным/структурам/функциям
вне пространства имён, нужно добавить к имени название пространства имён и оператор ::
В данном случае нужно добавить mipt::
*/
namespace mipt
{
int a = 5;
float b = 1.2;
int square(int x)
{
return x * x;
}
}
int main()
{
printf("%i\n", mipt::square(4));
}
/*
Задание:
1) Скомпилируйте программу и запустите, что она напечатает?
2) Что будет, если забыть написать mipt:: у названия функции square?
3) Передайте в функцию mipt::square переменную a из пространства имён mipt
4) Напишите функцию float average(float x, float y), которая будет принимать 2 числа
и возвращать их среднее арифметическое.
Поместите эту функцию в пространство имён mipt и вызовите эту функцию из main
5) Напечатайте среднее арифметическое от a и b, используя функцию average
*/

View file

@ -0,0 +1,25 @@
#include <stdio.h>
namespace mipt
{
int a = 5;
float b = 1.2;
int square(int x)
{
return x * x;
}
float average(float x, float y)
{
return (x + y) / 2;
}
}
int main()
{
printf("%i\n", mipt::square(mipt::a));
printf("%f\n", mipt::average(mipt::a, mipt::b));
}

View file

@ -0,0 +1,24 @@
#include <stdio.h>
/*
В языке C при объявлении структуры struct Book создаётся тип по имени struct Book.
В языке C++ при объявлении структуры struct Book создаётся тип к которому
можно обращаться как по имени struct Book так и по имени Book
*/
struct Book
{
char title[50];
int pages;
float price;
};
int main()
{
struct Book a = {"Tom Sawyer", 280, 500};
Book b = {"War and Peace", 1200, 900};
}

View file

@ -0,0 +1,40 @@
#include <cstdio>
/*
Определяем переменные/структуры/функции внутри пространства имён mipt
Затем к ним можно будет доступиться используя префикс mipt::
*/
namespace mipt
{
struct Book
{
char title[50];
int pages;
float price;
};
void printBook(Book b)
{
printf("%s, pages: %d, price: %.2f\n", b.title, b.pages, b.price);
}
}
int main()
{
}
/*
Задание:
Структура Book и функция printBook определены в пространстве имён mipt
1) Создайте переменную типа структура Book и иницилизируйте
её значениями: "War and Peace", 1200, 900
2) Напечатайте созданную переменную с помощью функции printBook
*/

View file

@ -0,0 +1,36 @@
#include <cstdio>
namespace mipt
{
struct Book
{
char title[50];
int pages;
float price;
};
void printBook(Book b)
{
printf("%s, pages: %d, price: %.2f\n", b.title, b.pages, b.price);
}
}
int main()
{
mipt::Book b = {"War and Peace", 1200, 900};
mipt::printBook(b);
}
/*
Задание:
Структура Book и функция printBook определены в пространстве имён mipt
1) Создайте переменную типа структура Book и иницилизируйте
её значениями: "War and Peace", 1200, 900
2) Напечатайте созданную переменную с помощью функции printBook
*/

View file

@ -0,0 +1,60 @@
#include <stdio.h>
/*
Зачем вообще нужны пространства имён?
Представьте, что вы создаёте большую программу, исходный код который
содержит миллионы строк кода. Конечно, большая часть кода написана не вами,
так как вы используете библиотеки, написанные другими программистами.
Библиотекой можно назвать совокупность файлов исходного кода, нацеленных
на решение какой-либо задачи. Например, есть библиотека для работы с графикой
в которой содержатся функции/структуры/классы для работы с графикой.
Если вы подключаете несколько библиотек, то существует высокая вероятность,
что название чего-либо из одной библиотеки совпадёт с названием чего-то из другой библиотеки.
Это, конечно, приведёт к ошибке.
Чтобы этого избежать и используются пространства имён.
*/
namespace audio
{
int a = 10;
int calculate(int x)
{
return x + 1;
}
}
namespace graphics
{
int a = 20;
int calculate(int x)
{
return x * 2;
}
}
int main()
{
printf("%i\n", audio::a);
printf("%i\n", graphics::a);
printf("%i\n", graphics::calculate(audio::calculate(graphics::a)));
}
/*
Задание:
1) Что напечатает данная программа?
*/

View file

@ -0,0 +1,78 @@
#include <stdio.h>
/*
Если вам очень не хочется постоянно писать названия пространства имён,
то вы можете использовать ключевое слово using
using namespace audio;
Это говорит о том, что начиная с этой строки audio:: перед именами писать больше не нужно
Это, конечно, полностью уничтожают всю пользу, которую приносят пространства имён.
То есть в больших проектах могут возникнуть ошибки, связанные с одинаковыми именами.
Так что так лучше не делать, а если и делать, то только в маленьких программах.
*/
namespace audio
{
int a = 10;
int calculate(int x)
{
return x + 1;
}
}
namespace graphics
{
int a = 20;
int calculate(int x)
{
return x * 2;
}
}
namespace network
{
int b = 20;
int solve(int x)
{
return x * 2;
}
}
using namespace audio;
int main()
{
printf("%i\n", calculate(a));
}
/*
Задание:
1) Что напечатает данная программа?
2) Если заменить using namespace audio на using namespace graphics, то что напечатает программа?
3) Что если одновременно использовать пространство имён audio и пространство имён graphics?
using namespace audio;
using namespace graphics;
Приведёт ли это к ошибке и, если да, то почему?
4) Что если одновременно использовать пространство имён audio и пространство имён network?
using namespace audio;
using namespace network;
Приведёт ли это к ошибке и, если да, то почему?
*/

View file

@ -0,0 +1,65 @@
#include <iostream>
/*
Все переменные/функции/структуры/классы стандартной библиотеки языка C++ содержатся в пространстве имён std
Рассмотрим, например, глобальную переменную cout, определённую в библиотеке iostream в пространстве имён std.
К этой переменной можно применять оператор <<
cout << объект
В результате этой операции объект напечатается на экран (если он может напечататься)
Результат оператора << также является cout, поэтому можно применять << несколько раз:
Например это выражение: cout << "Hello " << "World" << "\n";
1) Сначала напечатается "Hello " и на место cout << "Hello " подставится cout
Получтся cout << "World" << "\n";
2) Потом напечатется "World" и на место cout << "World" подставится cout
Получтся cout << "\n";
3) В конце напечатается перенос строки
*/
int main()
{
std::cout << "Hello World\n";
std::cout << 5 << "\n";
int x = 10;
std::cout << 5 << "\n";
}
/*
Задачи:
1) Напечатайте на экран число 1.4, используя cout (количество печатаемых знаков после запятой неважно)
Обратите внимание, что при печати с cout не нужно указывать спецификатор типа как в printf.
cout сам понимает объект какого типа ему передаётся
2) Напечатайте фразу "I am x years old", только за место x нужно подставить значение
переменной x. В данной задаче получится "I am 10 years old". Используйте cout.
3) Напечатайте на экран числа от 1 до 20, разделённые пробелом. Используйте cout
4) Вместо \n для переноса строки можно использовать endl - специальный объект из
пространства имён std.
Если мы передаём его объекту cout через оператор << то печатается перенос строки
Замените все переносы строк с \n на endl
std::cout << 5 << "\n"; --> std::cout << 5 << std::endl;
На самом деле std::endl работает медленней, чем \n, так как он помимо печати делает flush
Поэтому, если важна скорость печати в буфер, то лучше использовать \n
5) Что будет если не написать std:: перед одним из cout?
6) Используйте using namespace std; и избавьтесь от надоедливых std:: перед cout и endl
*/

View file

@ -0,0 +1,16 @@
#include <iostream>
using namespace std;
int main()
{
cout << 1.4 << endl;
int x = 10;
cout << "I am " << x << " years old" << endl;
for (int i = 1; i <= 20; ++i)
cout << i << " ";
cout << endl;
}

View file

@ -0,0 +1,32 @@
#include <iostream>
/*
В пространстве имён std очень много разных имён. Если мы добавим их всех, используя
using namespace std;
то это может привести к проблеме.
Одно из имён из std может совпасть с названием нашего объекта и это может привести к ошибке.
Так что лучше такую возможность не использовать.
Но можно добавить только одно имя так:
using std::cout;
Начиная с этого момента можно писать просто cout.
Но для всех остальных объектов из std вы должны продолжать писать std::
*/
using std::cout;
int main()
{
cout << "Hello World" << std::endl;
cout << 5 << std::endl;
}
/*
Задачи:
1) Добавить endl в нашу область видимости, также как и cout
*/

View file

@ -0,0 +1,41 @@
#include <iostream>
/*
Счтиывание из стандартного входа
Рассмотрим глобальную переменную cin, определённую в библиотеке iostream в пространстве имён std.
К этой переменной можно применять оператор >>
cin >> объект
В результате этой операции объект считается с экрана (если он может быть считан)
Результат оператора >> также является cin, поэтому можно применять >> несколько раз:
Например это выражение: cin >> a >> b;
1) Сначала считается переменная a и на место cin >> a подставится cin
Получтся cin >> b;
2) Потом считается переменная b
*/
int main()
{
int a, b;
std::cin >> a >> b;
std::cout << a + b;
}
/*
Задачи:
1) Что напечатает данная программа, если на вход передать числа 10 и 20?
2) Напишите программу, которая будет считывать два вещественных числа и печатать их среднее геометрическое
Функция корня sqrt есть в библиотеке <cmath>
*/

View file

@ -0,0 +1,10 @@
#include <iostream>
#include <cmath>
int main()
{
float a, b;
std::cin >> a >> b;
std::cout << sqrt(a * b);
}

View file

@ -0,0 +1,42 @@
#include <stdio.h>
#include <math.h>
/*
Язык C++ обратно совместим с языком C. То есть почти любая программа на C будет работать на C++
Эта программа будет работать.
Обратите внимания, для имён, пришедших из языка C использовать std:: не обязательно
Программа работает, несмотря на то, что мы используем библиотечные
функции printf и sqrt без указания пространства имён std.
*/
int main()
{
printf("%f", sqrt(3));
}
/* Задача:
1) Что напечатает данная программа?
2) Использование библиотечных функций без std опасно, так как может привести к ошибкам,
связанных с совпадением имён. Помните, что большая программа может иметь миллионы
строк кода и совпадение ваших имен и библиотечных имён очень вероятно.
Напишите следующую функцию перед функцией main
int sqrt(int x)
{
return x + 1;
}
Что теперь напечатает программа? Объясните результат.
*/

View file

@ -0,0 +1,37 @@
#include <cstdio>
#include <cmath>
/*
Желательно всё равно использовать std даже для имён пришедших из языка C
Также были изменены названия библиотек:
stdio.h --> cstdio
math.h --> cmath
cmath означает, что это библиотека языка C под названием math, поэтому и cmath
Они почти не отличаются от предыдущих, но при программировании на C++
желательно использовать именно эти библиотеки.
*/
int main()
{
std::printf("%f", std::sqrt(3));
}
/* Задача:
1) Что напечатает данная программа?
2) Напишите следующую функцию перед функцией main
int sqrt(int x)
{
return x + 1;
}
Что теперь напечатает программа? Объясните результат.
*/

View file

@ -0,0 +1,60 @@
#include <iostream>
using std::cout, std::endl;
/*
В C++ вводится понятие нового типа под названием Ссылка
Ссылку можно рассматривать как новое имя для объекта.
Ссылку также можно рассматривать как удобный указатель, который автоматически разыменовывается
(На самом деле под капотом ссылка и является указателем)
Ссылка объявляется с помощью значка & после имени типа.
Не стоит путать & используемый при объявлении ссылки с & используемым для нахождения адреса переменной.
Это разные &
Пусть есть переменная a
int a = 10;
Давайте создадим указатель и ссылку на эту переменную и увеличим её на 1 с помощью указателя/ссылки
Используем указатель: Используем ссылку:
int* p = &a; int& r = a;
*p += 1; r += 1;
Ссылкой пользоваться удобно, так как:
1) При создании ссылки нам не нужно передавать ей адрес
Просто передаём ей саму переменную, а ссылка уже сама находит её адрес
2) Не нужно её разыменовывать, она всегда разыменовывается сама
*/
int main()
{
int a = 10;
int& r = a;
r += 1;
cout << a << endl;
}
/*
Задачи:
1) Используйте ссылку r, чтобы увеличить a в 2 раза
Проверьте, как изменилась a, напечатав её
2) Используйте ссылку r, чтобы присвоить a число 100
Проверьте, как изменилась a, напечатав её
3) Создайте переменную b типа float, равную 1.5
Создайте ссылку на b и используйте эту ссылку, чтобы возвести b в квадрат
*/

View file

@ -0,0 +1,39 @@
#include <iostream>
using std::cout, std::endl;
/*
Пусть у нас есть некоторый объект, например
int a = 10;
После того как мы создали ссылку на этот объект
int& r = a;
Все (почти) операции применяемые к ссылке r применяются на самом деле к объекту a
Как будто у одного объекта теперь два имени a и r
Поэтому можно сказать, что ссылка это новое имя для объекта
При этом изменить саму ссылку (например, чтобы она начала указывать на другое имя) нельзя
*/
int main()
{
int a = 10;
int& r = a;
r += 5; // Прибавим к a число 5
r *= 2; // Умножим a на 2
cout << r << endl; // Напечатаем a
cout << sizeof(r) << endl; // Напечатаем размер a
cout << &r << endl; // Напечатаем адрес a
}
/*
Задачи:
1) Чему будет равно значение a в конце этой программы
*/

View file

@ -0,0 +1,43 @@
#include <iostream>
using std::cout, std::endl;
/*
Пусть у нас есть некоторый объект, например
int a = 10;
После того как мы создали ссылку на этот объект
int& r = a;
Все (почти) операции применяемые к ссылке r применяются на самом деле к объекту a
Как будто у одного объекта теперь два имени a и r
Поэтому можно сказать, что ссылка это новое имя для объекта
При этом изменить саму ссылку (например, чтобы она начала указывать на другое имя) нельзя
*/
int main()
{
int a[5] = {10, 20, 30, 40, 50};
int& b = a[1];
b += 1;
for (int i = 0; i < 5; ++i)
{
cout << a[i] << " ";
}
cout << endl;
}
/*
Задачи:
1) Что будет содержать массив a в конце данной программы?
2) Создайте ссылку, которая будет указывать на последний элемент массива a
Используйте эту ссылку, чтобы умножить последний элемент массива на 2
Напечатайте этот массив
*/

View file

@ -0,0 +1,49 @@
#include <iostream>
using std::cout, std::endl;
/*
Несмотря на то, что ссылки и указатели во многом похожи, у них есть и много больших отличий.
(помимо разной инициализации и того, что ссылку не нужно постоянно разыменовывать)
Различие 1)
Указатель можно создать без инициализации вот так:
int* p;
В этом случае в p будет храниться произвольный адрес.
Разыменовывать такой указатель, не задав его значение адресом какого-либо объекта,
очень опасно, это может привести к сложновыявляемым ошибкам.
Ссылку нельзя создать без инициализации, то есть так нельзя:
int& r;
При создании ссылки нужно указать на что она будет указывать
Различие 2)
Указатель можно приравнять нулевому значению
В C++ вводится специальное нулевое значение для указателя nullptr
Вместо NULL, который был просто равен числу 0. В C++ лучше использовать nullptr
Разыменование нулевого указателя также приведёт к ошибке.
Ссылку нельзя присвоить никакому нулевому значению
*/
int main()
{
}
/*
Задачи:
1) Попробуйте создать:
a) Указатель без инициализации
б) Ссылку без инициализации
в) Указатель, равнуй нулевому значению nullptr
г) Ссылку, равную нулю
Скомпилируется ли программа в этих 4-х случаях?
*/

View file

@ -0,0 +1,52 @@
#include <iostream>
using std::cout, std::endl;
/*
Несмотря на то, что ссылки и указатели во многом похожи, у них есть и много больших отличий.
(помимо разной инициализации и того, что ссылку не нужно постоянно разыменовывать)
Различие 3) Указатель можно переприсвоить. Если указатель сначала указывал в одно место,
например, на переменную a, то можно просто написать
p = &b;
и указатель станет указывать на переменную b.
Со ссылками такое не пройдёт, они всегда указывают на тот объект, который был указан при создании ссылки
При попытке изменить это и написать что-то вроде
r = b;
ссылка автоматически разыменуется и присваивание произойдёт к тому, на что указывала ссылка
*/
int main()
{
int a = 10;
int b = 20;
int* p = &a;
*p += 1;
p = &b;
*p += 1;
cout << a << " " << b << endl;
int& r = a;
r += 1;
r = b;
r += 1;
cout << a << " " << b << endl;
}
/*
Задачи:
1) Попробуйте понять, что напечатает программа без её запуска
2) Запустите программу, проверьте ваши догадки и объясните результат
*/

View file

@ -0,0 +1,44 @@
#include <iostream>
using std::cout, std::endl;
/*
Несмотря на то, что ссылки и указатели во многом похожи, у них есть и много больших отличий.
(помимо разной инициализации и того, что ссылку не нужно постоянно разыменовывать)
Различие 4)
Арифметика указателей.
К указателю можно прибавлять/отнимать целые числа. Можно вычесть 2 указателя.
Можно применить [] к указателю. При всём этом, желательно, чтобы указатель указывал на элемент массива.
Неаккуратное использование арифметики указателей может привести к ошибкам.
Например, можно прибавить к указателю не то число и выйти за пределы массива.
Ничего такого со ссылками сделать нельзя.
При попытке прибавить к ссылке число, оно прибавится к той переменной, на которую указывает ссылка.
Так как ссылка автоматически разыменуется.
*/
int main()
{
int a[5] = {10, 20, 30, 40, 50};
int* p = &a[0];
p += 1; // Увеличиваем указатель
*p += 1; // Увеличиваем то, на что указывает указатель
int& r = a[0];
r += 1; // Увеличиваем то, на что указывает ссылка (она автоматически разыменовывается)
}
/*
Задачи:
1) Чему будет равен массив a в конце данной программы
*/

View file

@ -0,0 +1,46 @@
#include <iostream>
using std::cout, std::endl;
/*
Несмотря на то, что ссылки и указатели во многом похожи, у них есть и много больших отличий.
Различие 5)
Ссылки это не совсем обычный объект, некоторые операции с ними запрещены:
Ссылку нельзя сделать элементом массива
Нельзя получить адрес ссылки (если применим & то вернётся адрес того объекта на который указывет ссылка)
Нельзя создать укатель на ссылку
Нельзя создать ссылку на ссылку
*/
int main()
{
int x = 1;
int y = 2;
int z = 2;
int& a[3] = {x, y, z}; // Ошибка, создать массив из ссылок не получится
}
/*
Задачи:
1) Можно ли инициализировать ссылку на int простым числом вот так:
int& r = 5;
2) Ссылку на ссылку создать нельзя, но код ниже почему-то работает.
Объясните почему этот код работает
int a = 10;
int& r1 = a;
int& r2 = r1;
r2 += 1;
*/

View file

@ -0,0 +1,69 @@
#include <iostream>
using std::cout, std::endl;
/*
В 90% случаях ссылки используются для того чтобы передать что либо в функцию
Часто нам хочется передать переменную в функцию и изменить её там (внутри функции)
Это можно делать и с помощью указателей, но с помощью ссылок это делать гораздо удобней
Рассмотрим два эквивалентных участка кода:
Передаём по указателю: Передаём по ссылке:
void sqr(int* p) void sqr(int& r)
{ {
*p = *p * *p; r = r * r;
} }
int main() int main()
{ {
int a = 5; int a = 5;
sqr(&a); sqr(a);
cout << a << endl; cout << a << endl;
} }
Обратите внимание на 2 вещи:
1) Ссылку не нужно разыменовывать внутри функции, это происходит автоматически
2) При передаче в функцию, не нужно передавать адрес переменной
Нужно передать саму переменную, компилятор сам вычислит её адрес
При этом копирования объекта a в функцию не происходит,
ссылки работают также быстро как и указатели
*/
void sqr(int& r)
{
r = r * r;
}
int main()
{
int a = 5;
sqr(a);
cout << a << endl;
}
/*
Задачи:
1) Напишите функцию void inc(int& x), которая должна принимать объект типа int
и увеличивать его на 1
Вызовите эту функцию из main и протестируйте её работу
2) Напишите функцию void normalize(float& x, float& y), которая должна принимать
2 объекта типа float и нормализировать их. То есть делить их на некоторое число,
так чтобы было x*x + y*y == 1
Для этого x и y нужно разделить на sqrt(x*x + y*y)
3) Можно ли передать в функцию sqr не переменную, а число?
То есть, можно ли написать так:
sqr(5)
*/

View file

@ -0,0 +1,50 @@
#include <iostream>
#include <cmath>
using std::cout, std::endl;
void inc(int& x)
{
x += 1;
}
void normalize(float& x, float& y)
{
float norm = std::sqrt(x * x + y * y);
x /= norm;
y /= norm;
}
int main()
{
int a = 5;
inc(a);
cout << a << endl;
float x = 9, y = 6;
normalize(x, y);
cout << x << " " << y << endl;
}
/*
Задачи:
1) Напишите функцию void inc(int& x), которая должна принимать объект типа int
и увеличивать его на 1
Вызовите эту функцию из main и протестируйте её работу
2) Напишите функцию void normalize(float& x, float& y), которая должна принимать
2 объекта типа float и нормализировать их. То есть делить их на некоторое число,
так чтобы было x*x + y*y == 1
Для этого x и y нужно разделить на sqrt(x*x + y*y)
3) Можно ли передать в функцию sqr не переменную, а число?
То есть, можно ли написать так:
sqr(5)
*/

View file

@ -0,0 +1,81 @@
#include <iostream>
using std::cout, std::endl;
/*
Чаще всего по ссылке в функцию передаются объекты структур и классов
Даже если мы не хотим менять объект внутри функции, мы всё-равно можем
захотеть передать его по ссылке, так как передача по ссылке не копирует объект,
следовательно это гораздо более эффективно
В этом случае передаём по константной ссылке (по аналогии с константным указателем)
*/
struct Book
{
char title[100];
int pages;
float price;
};
void increasePrice(Book& b, float value)
{
b.price += value;
}
void printBook(Book& b)
{
cout << b.title << ", pages = " << b.pages << ", price = " << b.price << endl;
}
int main()
{
Book b = {"War and Peace", 1200, 900};
printBook(b);
increasePrice(b, 100);
printBook(b);
}
/*
// Тот же самый код с использованием указателей выглядел бы так:
void increasePrice(Book* b, float value)
{
b->price += value;
}
void printBook(const Book* b)
{
cout << b->title << ", pages = " << b->pages << ", price = " << b->price << endl;
}
int main()
{
Book b = {"War and Peace", 1200, 900};
printBook(&b);
increasePrice(b, 100);
printBook(&b);
}
*/
/*
Задачи:
1) Напишите функцию addPage, которая бы принимала структуру Book по ссылке
и увеличивала количество страниц на 1
Протестируйте эту функцию в main
2) Напишите функцию changeFirstLetter, которая бы принимала структуру Book по ссылке
и изменяла первую букву в названии на букву A
*/

View file

@ -0,0 +1,41 @@
#include <iostream>
using std::cout, std::endl;
struct Book
{
char title[100];
int pages;
float price;
};
void addPage(Book& b)
{
b.pages++;
}
void changeFirstLetter(Book& b)
{
b.title[0] = 'A';
}
void printBook(const Book& b)
{
cout << b.title << ", pages = " << b.pages << ", price = " << b.price << endl;
}
int main()
{
Book b = {"War and Peace", 1200, 900};
printBook(b);
addPage(b);
printBook(b);
changeFirstLetter(b);
printBook(b);
}

View file

@ -0,0 +1,73 @@
#include <iostream>
using std::cout, std::endl;
/*
Ссылки, как и указатели используются для передачи объектов в функции
Рассмотрим три функции
incByValue - принимаем объект по значению
В этом случае объект копируется и функция работает с копией
incByPointer - принимаем объект по адресу
В этом случае внутри функции создаётся указатель, и в этот указатель
мы передаём адрес нашего объекта
incByReference - принимаем объект по ссылке
В этом случае происходит всё примерно то же самое, что и в случае incByPointer
Только с гораздо более приятным синтаксисом
*/
void incByValue(int a)
{
a += 1;
}
void incByPointer(int* p)
{
*p += 1;
}
void incByReference(int& a)
{
a += 1;
}
int main()
{
int a = 10;
cout << "1) Initial a = " << a << endl
incByValue(a);
cout << "2) After incByValue a = " << a << endl;
incByPointer(&a);
cout << "3) After incByPointer a = " << a << endl
incByReference(a);
cout << "4) After incByReference a = " << a << endl;
}
/*
Задание:
1) Напишите функции:
cubeByPointer(int* p) - принимет число по указателю и возводит это число в куб
cubeByReference(int& a) - принимет число по ссылке и возводит это число в куб
Протестируйте эти функции в main
2) Написать функции:
swapByPointer(int* pa, int* pb) - принимает 2 числа по указателю и обменивает их значения
swap(int& pa, int& pb) - принимает 2 числа по ссылке и обменивает их значения
Протестируйте эти функции в main
*/

View file

@ -0,0 +1,54 @@
#include <iostream>
using std::cout, std::endl;
void cubeByPointer(int* p)
{
*p = *p * *p * *p;
}
void cubeByReference(int& a)
{
a = a * a * a;
}
void swapByPointer(int* pa, int* pb)
{
int temp = *pa;
*pa = *pb;
*pb = temp;
}
void swapByReference(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
int main()
{
int a = 5;
cubeByPointer(&a);
cout << a << endl;
a = 5;
cubeByReference(a);
cout << a << endl;
int x = 10, y = 20;
swapByPointer(&x, &y);
cout << x << " " << y << endl;
x = 10;
y = 20;
swapByReference(x, y);
cout << x << " " << y << endl;
}

View file

@ -0,0 +1,97 @@
#include <iostream>
#include <cmath>
using std::cout, std::endl;
/*
Константные ссылки можно создать, используя ключевое слово const
int a = 10;
const int& r = a;
Это означает, что a нельзя будет изменить по этой ссылке
То есть поменять a, используя ссылку r будет нельзя:
r += 1; // Ошибка!
a += 1; // OK
Важным неочевидным отличием константных ссылок от обычных ссылок является то, что обычные ссылки
можно инициализировать только объектами, которые уже храняться в памяти (например, переменными).
int& r1 = a; // OK
int& r2 = 5; // Ошибка
Константные ссылки можно инициализировать чем угодно (нужно только чтобы тип совпадал)
const int& cr1 = a; // OK
const int& cr2 = 5; // OK
*/
int main()
{
int a = 10;
const int& r = a;
int& r1 = 20; // Это не будет компилироваться
const int& r2 = 20 // Тут всё ОК
}
/*
Задание:
1) Можно ли инициализировать ссылку таким образом?
float& r = std::sqrt(2);
Можно ли инициализировать константную ссылку таким образом?
const float& r = std::sqrt(2);
2) Пусть есть функция:
void printAgeV(int x)
{
cout << "My age is " << x << " years" << endl;
}
Можно ли вызвать её так?
int a = 10;
printAgeV(a)
Можно ли вызвать её так?
printAgeV(20)
3) Пусть есть функция:
void printAgeR(int& x)
{
cout << "My age is " << x << " years" << endl;
}
Можно ли вызвать её так?
int a = 10;
printAgeR(a)
Можно ли вызвать её так?
printAgeR(20)
4) Пусть есть функция:
void printAgeCR(const int& x)
{
cout << "My age is " << x << " years" << endl;
}
Можно ли вызвать её так?
int a = 10;
printAgeCR(a)
Можно ли вызвать её так?
printAgeCR(20)
*/

View file

@ -0,0 +1,63 @@
#include <iostream>
#include <cmath>
using std::cout, std::endl;
/*
Константные ссылки нужны прежде всего, чтобы передавать большие объекты в функции, внутри которых они не должны меняться
Рассмотрим структуру Book, чей размер более 100 байт
1) При передаче такой структуры в функцию по значению, как это происходит в функции printBookV,
вся структура будет копироваться внутрь функции и это очень медленно. Так делать не стоит.
2) При передаче такой структуры в функцию по обычной ссылке, как это происходит в функции printBookR, структура не копируется
На самом деле, под капотом внутрь функции копируется адрес структуры.
Адрес намного меньше самой структуры, поэтому это копирование работает намного быстрее.
Но возникает проблема с тем, что структура внутри такой функции может поменяться.
В реальной ситуации, если функций много и они большие, уследить за тем меняется ли аргументы внутри функций становится проблематично.
3) При передаче такой структуры в функцию по константной ссылке, как это происходит в функции printBookCR, структура не копируется.
Плюс к этому мы можем быть уверены, что внутри функции наша структура не поменяется и это сильно упрощает понимание программы.
*/
struct Book
{
char title[100];
int pages;
float price;
};
void printBookV(Book b)
{
cout << b.title << ", pages = " << b.pages << ", price = " << b.price << endl;
}
void printBookR(Book& b)
{
cout << b.title << ", pages = " << b.pages << ", price = " << b.price << endl;
}
void printBookCR(const Book& b)
{
cout << b.title << ", pages = " << b.pages << ", price = " << b.price << endl;
}
int main()
{
Book b = {"War and Peace", 1200, 900};
printBookV(b);
printBookR(b);
printBookCR(b);
}

View file

@ -0,0 +1,50 @@
#include <iostream>
using std::cout, std::endl;
/*
Ссылки можно и возвращать из функции
Например, функция get возвращает ссылку на глобальную переменную x
*/
int x = 10;
int& get()
{
return x;
}
int main()
{
cout << x << endl;
cout << get() << endl;
get() += 1;
cout << x << endl;
}
/*
С указателями аналогичный код выглядел бы так:
int x = 10;
int* get()
{
return &x;
}
int main()
{
cout << x << endl;
cout << *get() << endl;
*get() += 1;
cout << x << endl;
}
*/

View file

@ -0,0 +1,51 @@
#include <iostream>
using std::cout, std::endl;
/*
Ссылки можно и возвращать из функции
Но при этом нужно следить за тем, чтобы функция не вернула ссылку на локальную переменную, как это происходит в данном примере.
После завершения функции, переменная x удалится, так как она была определена внутри функции.
В результате, внутри функции main мы попробуем доступиться к области памяти, в которой раньше лежала переменная x.
Это приведёт к ошибке
*/
int& get()
{
int x = 10;
return x;
}
int main()
{
cout << get() << endl;
get() += 1;
cout << get() << endl;
}
/*
Аналогичная ошибка может произойти и при работе с обычными указателями:
int* get()
{
int x = 10;
return &x;
}
int main()
{
cout << *get() << endl;
*get() += 1;
cout << *get() << endl;
}
*/

View file

@ -0,0 +1,39 @@
#include <iostream>
using std::cout, std::endl;
/*
Ссылки можно и возвращать из функции
Например, функция increase принимает ссылку, увеличивет то, на что указывает эта ссылка на 1
и возвращает эту ссылку
При этом никакого копирование самой переменной a в функцию и из функции не происходит
*/
int& increase(int& r)
{
r += 1;
return r;
}
int main()
{
int a = 10;
cout << "1) a = " << a << endl;
increase(a);
cout << "2) a = " << a << endl;
increase(a) += 7;
cout << "3) a = " << a << endl;
increase(increase(increase(a)));
cout << "4) a = " << a << endl;
}
/*
Что напечатает данная программа?
*/

View file

@ -0,0 +1,17 @@
#include <iostream>
using std::cout, std::endl;
/*
Задача:
Напишите функцию multiplyBy2, которая принимает число по ссылке и увеличивает его в 2 раза
Вызовите эту функцию из функции main
*/
int main()
{
}

View file

@ -0,0 +1,16 @@
#include <iostream>
using std::cout, std::endl;
void multiplyBy2(int& a)
{
a *= 2;
}
int main()
{
int x = 10;
multiplyBy2(x);
cout << x << endl;
}

View file

@ -0,0 +1,22 @@
#include <iostream>
using std::cout, std::endl;
/*
Задача:
Напишите функцию sumAndSave, которая должна принимать 3 аргумента
Первые два аргумента по значению
Третий аргумент по ссылке
Функция должна складывать первые 2 аргумента и сохранять результат по третей ссылке
Вызовите эту функцию из функции main
*/
int main()
{
}

View file

@ -0,0 +1,36 @@
#include <iostream>
using std::cout, std::endl;
/*
Задача:
Напишите функцию sumAndSave, которая должна принимать 3 аргумента
Первые два аргумента по значению
Третий аргумент по ссылке
Функция должна складывать первые 2 аргумента и сохранять результат по третей ссылке
Вызовите эту функцию из функции main
*/
void sumAndSave(int a, int b, int& c)
{
c = a + b;
}
int main()
{
int x = 10, y = 20;
int z;
sumAndSave(x, y, z);
cout << z << endl;
sumAndSave(70, 80, z);
cout << z << endl;
}

View file

@ -0,0 +1,28 @@
#include <iostream>
using std::cout, std::endl;
/*
Задача:
Напишите функцию
void calculateLetters(char str[], int& numLetters)
Которая будет принимать на вход строку и считать количество строчных букв в этой строке
Строчные буквы - это символы от 'a' и до 'z'
Например, вызов calculateLetters("ab54AB,gd1:e", x) должен сохранить число 5 в переменную x
*/
int main()
{
int x;
calculateLetters("ab54AB,gd1:e", x);
cout << x << endl;
}

View file

@ -0,0 +1,23 @@
#include <iostream>
using std::cout, std::endl;
void calculateLetters(char str[], int& numLetters)
{
numLetters = 0;
for (int i = 0; str[i] != '\0'; ++i)
{
if (str[i] >= 'a' && str[i] <= 'z')
numLetters += 1;
}
}
int main()
{
int x;
calculateLetters("ab54AB,gd1:e", x);
cout << x << endl;
}

View file

@ -0,0 +1,61 @@
#include <stdio.h>
/*
Это программа на языке C и компилировать её надо так:
gcc 00cfunctions.c
Известно, что в языке C нельзя создать две функции с одинаковым названием
Но часто требуется написать функции, которые будут делать похожие вещи, но для разных типов данных.
Простейший пример -- математические функции для разных численных типов данных
В языке C эта проблема решается так, что функциям даются немного различающиеся имена
В данном примере мы создали функции для вычисления абсолютного значения для типов int и double
Всё работает хорошо, пока мы соблюдаем типы данных и функции
Но стоит ошибиться и произойдёт сложно выявляемая ошибка
*/
int abs(int a)
{
if (a < 0)
return -a;
else
return a;
}
double fabs(double a)
{
if (a < 0)
return -a;
else
return a;
}
int main()
{
printf("%i\n", abs(-5));
printf("%lf\n", fabs(-5.9));
double x = abs(-5.9);
printf("%lf\n", x);
}
/*
Задача:
1) В данном примере переменная x равна ровно 5. Почему так происходит?
2) Что будет, если всё-таки назвать 2 функции одинаковым именем и скомпилировать программу с помощью gcc?
*/

View file

@ -0,0 +1,66 @@
#include <iostream>
using std::cout, std::endl;
/*
Это программа на языке C++ и компилировать её надо так:
g++ 01cppfunctions.c
В отличии от языка C в языке C++ есть возможность создать 2 и больше разных функции с одним и тем же названием,
но с разным количеством и/или типами аргументов.
Компилятор сам догадается, какую функцию следует вызвать в зависимости от типа аргумента.
*/
int abs(int a)
{
if (a < 0)
return -a;
else
return a;
}
double abs(double a)
{
if (a < 0)
return -a;
else
return a;
}
int main()
{
cout << abs(-5) << endl;
cout << abs(-5.9) << endl;
double x = abs(-5.9);
cout << x << endl;
}
/*
Задачи:
1) Протестируйте, что компилятор действительно вызывает нужные функции
Для этого просто сделайте так, чтобы функция, которая принимает int печатала на экран слово int,
а функция, которая принимает double, печатала бы на экран слово double
2) Что если на вход функции abs передать тип float?
Например, вот так:
abs(1.5f)
Какая из функций вызовется?
3) Напишите ещё одну перегрузку функции abs для типа float
Протестируйте её в функции main
*/

View file

@ -0,0 +1,30 @@
#include <iostream>
using std::cout, std::endl;
/*
Задача:
Напишите несколько перегруженных функций под названием max
1) max, который вычисляет максимум от двух чисел типа int
2) max, который вычисляет максимум от двух чисел типа double
3) max, который вычисляет максимум от трёх чисел типа int
4) max, который вычисляет максимум от трёх чисел типа double
*/
int max(int a, int b)
{
if (a > b)
return a;
else
return b;
}
int main()
{
cout << max(4.2, 2.8) << endl; // Выводит число 4 -- неправильно
}

View file

@ -0,0 +1,53 @@
#include <iostream>
using std::cout, std::endl;
int max(int a, int b)
{
if (a > b)
return a;
else
return b;
}
double max(double a, double b)
{
if (a > b)
return a;
else
return b;
}
int max(int a, int b, int c)
{
int result = a;
if (b > result)
result = b;
if (c > result)
result = c;
return result;
}
double max(double a, double b, double c)
{
double result = a;
if (b > result)
result = b;
if (c > result)
result = c;
return result;
}
int main()
{
cout << max(4.2, 2.8) << endl;
cout << max(1, 2) << endl;
cout << max(4, 2, 5) << endl;
cout << max(1.2, 2.1, 0.5) << endl;
}

View file

@ -0,0 +1,42 @@
#include <iostream>
using std::cout, std::endl;
/*
Задача:
Напишите несколько перегруженных функций под названием printType
Эти функции должны печатать тип переменной, которая поступает на вход
printType(15) должен напечатать int
printType(1.5) должен напечатать double
printType(1.5f); должен напечатать float
printType("Hello"); должен напечатать char[]
book b = {"War and Peace", 900, 1200};
printType(b); должен напечатать book
*/
struct book
{
char title[50];
float price;
int pages;
};
int main()
{
printType(15);
printType(1.5);
printType(1.5f);
printType("Hello");
book b = {"War and Peace", 900, 1200};
printType(b);
}

View file

@ -0,0 +1,66 @@
#include <iostream>
using std::cout, std::endl;
/*
Задача:
Напишите несколько перегруженных функций под названием printType
Эти функции должны печатать тип переменной, которая поступает на вход
printType(15) должен напечатать int
printType(1.5) должен напечатать double
printType(1.5f); должен напечатать float
printType("Hello"); должен напечатать char[]
book b = {"War and Peace", 900, 1200};
printType(b); должен напечатать book
*/
struct book
{
char title[50];
float price;
int pages;
};
void printType(int a)
{
cout << "int" << endl;
}
void printType(double a)
{
cout << "double" << endl;
}
void printType(float a)
{
cout << "float" << endl;
}
void printType(const char a[])
{
cout << "char[]" << endl;
}
void printType(const book& a)
{
cout << "book" << endl;
}
int main()
{
printType(15);
printType(1.5);
printType(1.5f);
printType("Hello");
book b = {"War and Peace", 900, 1200};
printType(b);
}

View file

@ -0,0 +1,17 @@
#include <iostream>
#include <cmath>
using std::cout, std::endl;
/*
В отличии от языка C в языке C++ стандартные математические функции уже перегружены и могут
работать с разными типами данных
*/
int main()
{
cout << std::abs(-4) << endl;
cout << std::abs(-4.2) << endl;
cout << std::abs(-4.2f) << endl;
}

View file

@ -0,0 +1,67 @@
#include <iostream>
using std::cout, std::endl;
/*
Функции можно перегружать и по указателю и ссылке
Но в случае с перегрузкой по ссылке могут возникнуть ситуации при которых невозможно выбрать правильный
Например, при вызове
int a = 10;
func(a);
Можно выбрать функцию void func(int x) или void func(int& x)
Определить более правильную функцию в этом случае невозможно, это приведёт к ошибке
*/
void func(int x)
{
cout << "int x" << endl;
}
void func(int* x)
{
cout << "int* x" << endl;
}
void func(int& x)
{
cout << "int& x" << endl;
}
int main()
{
int a = 10;
int* p = &a;
int& r = a;
func(a);
}
/*
Задачи:
1) Определите какая функция вызовется при следующих вызовах функции func или произойдёт ошибка
1) func(a)
2) func(p)
3) func(&a)
4) func(20)
5) func(r)
6) func(&r)
2) Если добавить перегрузку, принимающую по константной ссылке, то что изменится
void func(const int& x)
{
cout << "const int& x" << endl;
}
*/

View file

@ -0,0 +1,30 @@
#include <iostream>
using std::cout, std::endl;
struct Cat {};
struct Dog {};
struct Cow {};
void say(Cat a)
{
cout << "Meow" << endl;
}
void say(Dog a)
{
cout << "Woof" << endl;
}
void say(Cow a)
{
cout << "Mooo" << endl;
}
int main()
{
Cow x;
say(x);
}

View file

@ -0,0 +1,48 @@
#include <iostream>
using std::cout, std::endl;
/*
Предположим, что мы захотели создать структуру, который будет хранить время (для простоты, только минуты и секунды)
Нам может понадобиться функция, которая будет добавлять ко времени, некоторое количество секунд
*/
struct Time
{
int minutes;
int seconds;
};
Time add(Time t, int x)
{
Time result = t;
result.seconds += x;
result.minutes += (result.seconds / 60);
result.seconds %= 60;
return result;
}
int main()
{
Time a = {20, 10};
Time b = add(a, 90);
cout << b.minutes << " " << b.seconds << endl;
}
/*
Задача:
1) Напишите функцию, которая будет складывать не время и число, а два времени
Time add(Time ta, Time tb)
*/

View file

@ -0,0 +1,44 @@
#include <iostream>
using std::cout, std::endl;
struct Time
{
int minutes;
int seconds;
};
Time add(Time t, int x)
{
Time result = t;
result.seconds += x;
result.minutes += (result.seconds / 60);
result.seconds %= 60;
return result;
}
Time add(Time ta, Time tb)
{
Time result = ta;
result.seconds += 60 * tb.minutes + tb.seconds;
result.minutes += (result.seconds / 60);
result.seconds %= 60;
return result;
}
int main()
{
Time a = {20, 10};
Time b = add(a, 90);
Time c = add(a, b);
cout << b.minutes << " " << b.seconds << endl;
cout << c.minutes << " " << c.seconds << endl;
}

View file

@ -0,0 +1,63 @@
#include <iostream>
using std::cout, std::endl;
/*
Использовать функции может быть не так удобно как операторы.
Возможно было бы удобней для добавления времени использовать не функцию add, а оператор +
Можно перегрузить оператор функцией, для этого нужно назвать функцию так: operator@
где за место @ нужно подставить оператор, который вы хотите перегрузить
Например, функция Time operator+(Time t, int x) перегружает оператор + для типов Time и int соответственно (обязательно в таком порядке)
Теперь, когда компилятор встретит в коде сложение с таким операндами он вызовет эту функцию
В этом примере a + 90 при компиляции преобразуется в вызов функции operator+(a, 90)
*/
struct Time
{
int minutes;
int seconds;
};
Time operator+(Time t, int x)
{
Time result = t;
result.seconds += x;
result.minutes += (result.seconds / 60);
result.seconds %= 60;
return result;
}
int main()
{
Time a = {20, 10};
Time b = a + 90;
cout << b.minutes << " " << b.seconds << endl;
}
/*
Задача:
1) Что если операторы сложения поменяются местами
Time b = 90 + a;
Сработает ли в этом случае наша функция operator+ и, если нет, что нужно добавить, чтобы такое сложение сработало?
2) Напишите перегруженный оператор, который будет складывать не время и число, а два времени
Time operator+(Time ta, Time tb)
*/

View file

@ -0,0 +1,50 @@
#include <iostream>
using std::cout, std::endl;
struct Time
{
int minutes;
int seconds;
};
Time operator+(Time t, int x)
{
Time result = t;
result.seconds += x;
result.minutes += (result.seconds / 60);
result.seconds %= 60;
return result;
}
Time operator+(int x, Time t)
{
return t + x;
}
Time operator+(Time ta, Time tb)
{
Time result = ta;
result.seconds += 60 * tb.minutes + tb.seconds;
result.minutes += (result.seconds / 60);
result.seconds %= 60;
return result;
}
int main()
{
Time a = {20, 10};
Time b = a + 90;
Time c = 90 + a;
Time d = a + b;
cout << b.minutes << " " << b.seconds << endl;
cout << c.minutes << " " << c.seconds << endl;
cout << d.minutes << " " << d.seconds << endl;
}

View file

@ -0,0 +1,71 @@
#include <iostream>
using std::cout, std::endl;
/*
Помимо перегрузки операторов, принимающих 2 аргумента (бинарных)
можно перегружать и унарные операторы - принимающие один аргумент
При этом, так как operator+ это функция, то работает перегрузка функций
*/
struct Time
{
int minutes;
int seconds;
};
Time operator+(Time ta, Time tb)
{
cout << "binary operator +" << endl;
Time result = ta;
result.seconds += 60 * tb.minutes + tb.seconds;
result.minutes += (result.seconds / 60);
result.seconds %= 60;
return result;
}
Time operator+(Time t)
{
cout << "unary operator +" << endl;
return t;
}
int main()
{
Time a = {20, 10};
Time b = {40, 30};
Time c = a + b;
Time d = +a;
cout << c.minutes << " " << c.seconds << endl;
cout << d.minutes << " " << d.seconds << endl;
}
/*
Задача:
1) Что если операторы сложения поменяются местами
Time b = 90 + a;
Сработает ли в этом случае наша функция operator+ и, если нет, что нужно добавить, чтобы такое сложение сработало?
2) Напишите перегруженный оператор, который будет складывать не время и число, а два времени
Time operator+(Time ta, Time tb)
*/

View file

@ -0,0 +1,38 @@
#include <iostream>
using std::cout, std::endl;
/*
В прошлом семестре, для хранения результатов логических операций, мы использовали целочисленные типы (например int).
В языке C++ есть встроенный тип bool, который может принимать 2 значения (true и false).
Для хранения значения логических переменных желательно использовать этот тип
При печати на экран с помощью std::cout переменных типа bool печатается либо 0 либо 1
Чтобы на экран печаталось false или true нужно в std::cout передать специальный объект std::boolalpha
*/
bool isEven(int a)
{
return a % 2 == 0;
}
int main()
{
bool a = isEven(10);
bool b = isEven(15);
bool c = a || b;
if (c)
cout << "Yes" << endl;
else
cout << "No" << endl;
cout << c << endl;
cout << std::boolalpha << c << endl;
}

View file

@ -0,0 +1,68 @@
#include <iostream>
using std::cout, std::endl;
/*
Помимо арифметических операторов можно перегружать и операторы сравнения (и многие другие операторы)
Желательно, чтобы операторы сравнения возвращали bool
*/
struct Time
{
int minutes;
int seconds;
};
Time operator+(Time ta, Time tb)
{
Time result = ta;
result.seconds += 60 * tb.minutes + tb.seconds;
result.minutes += (result.seconds / 60);
result.seconds %= 60;
return result;
}
bool operator>(Time ta, Time tb)
{
bool result = false;
if (ta.minutes > tb.minutes)
result = true;
else if (ta.minutes == tb.minutes && ta.seconds > tb.seconds)
result = true;
return result;
}
int main()
{
Time a = {10, 20};
Time b = {10, 40};
Time c = {0, 20};
cout << std::boolalpha;
cout << (a > b) << endl;
cout << (b > a) << endl;
cout << (a + c > b) << endl;
}
/*
Задача:
1) Заметьте, что при выводе на экран сравнение было взято в скобки
cout << (a > b) << endl;
Что будет, если эти скобки не писать и почему
cout << a > b << endl;
2) Напишите перегруженные операторы < >= <= == != для сравнения объектов структур типа Time друг с другом
*/

View file

@ -0,0 +1,110 @@
#include <iostream>
using std::cout, std::endl;
/*
Помимо арифметических операторов можно перегружать и операторы сравнения (и многие другие операторы)
Желательно, чтобы операторы сравнения возвращали bool
*/
struct Time
{
int minutes;
int seconds;
};
Time operator+(Time ta, Time tb)
{
Time result = ta;
result.seconds += 60 * tb.minutes + tb.seconds;
result.minutes += (result.seconds / 60);
result.seconds %= 60;
return result;
}
bool operator>(Time ta, Time tb)
{
bool result = false;
if (ta.minutes > tb.minutes)
result = true;
else if (ta.minutes == tb.minutes && ta.seconds > tb.seconds)
result = true;
return result;
}
bool operator==(Time ta, Time tb)
{
bool result = false;
if (ta.minutes == tb.minutes && ta.seconds == tb.seconds)
result = true;
return result;
}
bool operator!=(Time ta, Time tb)
{
return !(ta == tb);
}
bool operator>=(Time ta, Time tb)
{
return ta > tb || ta == tb;
}
bool operator<(Time ta, Time tb)
{
return !(ta >= tb);
}
bool operator<=(Time ta, Time tb)
{
return !(ta > tb);
}
int main()
{
Time a = {10, 20};
Time b = {10, 40};
Time c = {0, 20};
cout << std::boolalpha;
cout << (a == b) << endl;
cout << (a != b) << endl;
cout << (a < b) << endl;
cout << (a <= b) << endl;
cout << (a > b) << endl;
cout << (a >= b) << endl;
cout << (a + c >= b) << endl;
}
/*
Задача:
1) Заметьте, что при выводе на экран сравнение было взято в скобки
cout << (a > b) << endl;
Что будет, если эти скобки не писать и почему
cout << a > b << endl;
Ошибка происходит из-за того, что приоритет операции << выше, чем у операций сравнения
В результате сначала проводится
cout << a
затем получившийся объект сравнивается с b. Это и приводит к ошибке.
*/

View file

@ -0,0 +1,49 @@
#include <iostream>
using std::cout, std::endl;
/*
Перегрузка оператора << для вывода на экран
Напомним, что объект под названием cout имеет тип ostream (сокращение от output stream - выходной поток)
и хранится в библиотеке iostream в пространстве имён std
То есть где-то внутри библиотеки iostream объявлена глобальная переменная по имени cout типа ostream
ostream cout;
Мы можем перегрузить оператор << с первым аргументом типа std::ostream, а вторым аргументом - нашим типом,
чтобы удобно выводить на экран объекты нашего типа.
*/
struct Time
{
int minutes;
int seconds;
};
void operator<<(std::ostream& out, Time t)
{
out << t.minutes << ":" << t.seconds;
}
int main()
{
Time a = {10, 20};
cout << a;
}
/*
Задача:
cout << a; работает, но
cout << a << endl; выдаёт ошибку в данной программе.
Из-за чего это происходит и как исправить эту ошибку?
*/

View file

@ -0,0 +1,63 @@
#include <iostream>
using std::cout, std::endl;
struct Time
{
int minutes;
int seconds;
};
Time operator+(Time ta, Time tb)
{
Time result = ta;
result.seconds += 60 * tb.minutes + tb.seconds;
result.minutes += (result.seconds / 60);
result.seconds %= 60;
return result;
}
std::ostream& operator<<(std::ostream& out, Time t)
{
out << t.minutes << ":" << t.seconds;
return out;
}
int main()
{
Time a = {10, 20};
Time b = {15, 50};
cout << a << endl << b << endl;
cout << a + b << endl;
}
/*
Задача:
cout << a; работает, но
cout << a << endl; выдаёт ошибку в данной программе.
Из-за чего это происходит и как исправить эту ошибку?
Решение:
Ошибка происходила из-за того, что оператор << ничего не возвращал.
В строке cout << a << endl;
результат cout << a был void и к нему нельзя применить оператор << ещё раз.
Результат cout << a должен быть тоже быть равен cout
Но, поскольку глобальный объект cout копировать мы не можем, у нас остаётся единственный выход:
принимать и возвращать объект cout по ссылке.
*/

View file

@ -0,0 +1,52 @@
#include <iostream>
using std::cout, std::endl;
struct Complex
{
float re, im;
};
Complex operator+(Complex first, Complex second)
{
Complex result = {first.re + second.re, first.im + second.im};
return result;
}
int main()
{
Complex z1 = {3, 7};
Complex z2 = {2, -4};
Complex z = z1 + z2;
cout << z.re << " + " << z.im << "i" << endl;
}
/*
Задачи:
1) Перегрузите следующие операторы:
- Вычитание
- Умножение
- Деление
- Унарный минус
- Унарный плюс
- Сравнение ==
- Сопряжение - это операция, которая меняет знак мнимой части комплексного числа
Для сопряжения используйте оператор унарная звёздочка *
2) Перегрузите оператор вывода <<
3) Напишите функцию exp(z)
/*
cout << z1 - z2 << endl;
cout << z1 * z2 << endl;
cout << z1 / z2 << endl;
cout << -z1 << endl;
cout << *z1 << endl; // (Комплексно-сопряжённое)
z = exp(z1 + z2)/(z1 * z2);
cout << z << endl;
*/

View file

@ -0,0 +1,52 @@
#include <iostream>
#include <iomanip>
using std::cout, std::endl;
/*
В библиотеки iomanip содержатся специальные функции, для работы с потоками ostream
setw - установить минимальный размер в символах для печати следующего объекта
setfill - если размер печати меньше минимального, то замостить оставшееся соответствующим символом
setprecision - установить точность (для вещественных чисел)
*/
struct Time
{
int minutes;
int seconds;
};
Time operator+(Time ta, Time tb)
{
Time result = ta;
result.seconds += 60 * tb.minutes + tb.seconds;
result.minutes += (result.seconds / 60);
result.seconds %= 60;
return result;
}
std::ostream& operator<<(std::ostream& out, Time t)
{
out << std::setfill('0') << std::setw(2) << t.minutes << ":" <<
std::setfill('0') << std::setw(2) << t.seconds;
return out;
}
int main()
{
Time a = {1, 5};
Time b = {4, 20};
cout << a << endl << b << endl;
cout << a + b << endl;
}

View file

@ -0,0 +1,52 @@
#include <iostream>
#include <cstdlib>
using std::cout, std::endl;
/*
В отличии от языка C, язык C++ не делает неявное преобразование типов указателей.
Рассмотрим, например, код:
int a = 10;
char* p = &a;
В языке C такой код сработает, несмотря на то, что в строке char* p = &a; слева стоит указатель типа char*
а справа объект типа int*. Будет произведено неявное преобразование типов указателей.
В языке C++ такой код приведёт к ошибке, так как C++ не преобразует указатели неявно.
Рассмотрим, например, код:
int* q = malloc(10 * sizeof(int));
В языке C такой код сработает, несмотря на то, что слева стоит указатель типа int*
а справа объект типа void* (malloc возвращает указатель типа void*).
Будет произведено неявное преобразование типов указателей.
В языке C++ такой код приведёт к ошибке, так как C++ не преобразует указатели неявно.
*/
int main()
{
int a = 10;
char* p = &a;
int* q = malloc(10 * sizeof(int));
}
/*
Задача:
Исправьте ошибки компиляции, явно приведя указатель к правильным типам.
*/

View file

@ -0,0 +1,13 @@
#include <iostream>
#include <cstdlib>
using std::cout, std::endl;
int main()
{
int a = 10;
char* p = (char*)&a;
int* q = (int*)malloc(10 * sizeof(int));
}

View file

@ -0,0 +1,17 @@
#include <iostream>
#include <cstdlib>
using std::cout, std::endl;
/*
В языке C++ желательно использовать более безопасное приведение типов static_cast
*/
int main()
{
int a = 10;
char* p = static_cast<char*>(&a);
int* q = static_cast<int*>(malloc(10 * sizeof(int)));
}

View file

@ -0,0 +1,50 @@
#include <cstdio>
/*
Новое специальное нулевое значение для указателя: nullptr
В языке C для этой цели использовался NULL, который был просто числом 0
Если определить NULL так:
#define NULL (void*)0
То, в отличии от языка C, в языке C++ простая строка вида:
int* p = NULL;
не сработает, так как слева стоит int* а справа void*
Если определить NULL так:
#define NULL 0
то в C++ могут возникнуть проблемы с перегрузкой, как это показано ниже.
*/
void print(int value)
{
printf("Int: %d\n", value);
}
void print(void* pointer)
{
printf("Pointer: %p\n", pointer);
}
int main()
{
void* p1 = NULL;
void* p2 = nullptr;
// Всё ОК (компилятор может выбрать функцию):
print(p1);
print(p2);
// Тут неверно (компилятор не может выбрать перегруженную функцию, произойдёт ошибка):
print(NULL);
// Тут всё OK:
print(nullptr);
}

View file

@ -0,0 +1,42 @@
#include <iostream>
using std::cout, std::endl;
/*
В отличии от языка C, в C++ можно задавать значения по умолчанию
для аргументов функций
Функцию printSquare можно вызвать с одним, двумя или тремя
параметрами. Аргументы width и height будут заданы аргументами по умолчанию.
Если передаваемых аргументов будет меньше трёх.
*/
void printSquare(char c, int width = 10, int height = 5)
{
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
cout << c;
}
cout << endl;
}
}
int main()
{
printSquare('+', 6, 4);
printSquare('#', 15);
printSquare('O');
}
/*
Задание:
1) Написать функцию:
void print(char str[], bool isCapitalized = false)
Которая будет просто печатать строку str, если isCapitalized = false,
а если isCapitalized = true, то будет печатать всю строку в верхнем регистре
*/

View file

@ -0,0 +1,189 @@
#pragma once
#include <cmath>
#include <iostream>
struct Complex {
float re;
float im;
};
// Передаёмм аргументы через ссылки
// В данном случае можно было передавать по значению
// (так как Complex имеет малый размер)
// Но в общем случае лучше для структур лучше
// всегда использовать ссылки
Complex operator+(const Complex& a, const Complex& b) {
Complex result = {a.re + b.re, a.im + b.im};
return result;
}
Complex operator-(const Complex& a, const Complex& b) {
Complex result = {a.re - b.re, a.im - b.im};
return result;
}
Complex operator*(const Complex& a, const Complex& b) {
Complex result = {a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re};
return result;
}
Complex operator/(const Complex& a, const Complex& b) {
float b_squared = b.re * b.re + b.im * b.im;
Complex result;
result.re = (a.re * b.re + a.im * b.im) / b_squared;
result.im = (a.im * b.re - a.re * b.im) / b_squared;
return result;
}
Complex& operator+=(Complex &a, const Complex &b) {
a.re += b.re;
a.im += b.im;
return a;
}
// Унарный оператор -
// То есть если z - комплексное число x + iy, то -z = - x - iy
Complex operator-(const Complex& a) {
Complex result;
result.re = -a.re;
result.im = -a.im;
return result;
}
// Унарный оператор +
// Ничего не меняет
Complex operator+(const Complex& a) {
Complex result = a;
return result;
}
// Унарный оператор *
// То есть если z - комплексное число x + iy, то *z = x - iy
// Оператор сопряжения
Complex operator*(const Complex& a) {
Complex result;
result.re = a.re;
result.im = -a.im;
return result;
}
// Число + комплексное число (в таком порядке)
Complex operator+(float a, const Complex& b) {
Complex result = b;
result.re += a;
return result;
}
// Комплексное число + число
Complex operator+(const Complex& a, float b) {
Complex result = a;
result.re += b;
return result;
}
// Число - комплексное число (в таком порядке)
Complex operator-(float a, const Complex& b) {
Complex result = -b;
result.re += a;
return result;
}
// Комплексное число - число
Complex operator-(const Complex& a, float b) {
Complex result = a;
result.re -= b;
return result;
}
// Комплексное число * число
Complex operator*(const Complex& a, float b) {
Complex result = a;
result.re *= b;
result.im *= b;
return result;
}
// Число * комплексное число
Complex operator*(float a, const Complex& b) {
Complex result = b;
result.re *= a;
result.im *= a;
return result;
}
// Комплексное число / число
Complex operator/(const Complex& a, float b) {
Complex result = a;
result.re /= b;
result.im /= b;
return result;
}
// Число / комплексное число
Complex operator/(float a, const Complex& b) {
float b_squared = b.re * b.re + b.im * b.im;
return (a * (*b)) / b_squared;
}
// Перегружаем оператор<< между типами
// std::ostream (такой тип имеет std::cout) и Complex
// Обратите внимание, что мы возвращаем ссылку на ostream
// Таким образом результатом выражения cout << a будет cout
// Поэтому можно делать так: cout << a << b << c ...
std::ostream& operator<<(std::ostream& out, const Complex& a) {
if (a.re != 0)
out << a.re;
if (a.im > 0) {
if (a.im != 1.0)
out << " + " << a.im << "i";
else
out << " + i";
}
else if (a.im < 0) {
if (a.im != -1.0)
out << " - " << -a.im << "i";
else
out << " - i";
}
return out;
}
std::istream& operator>>(std::istream& in, Complex& c) {
in >> c.re >> c.im;
return in;
}
float abs(const Complex& a) {
return sqrtf(a.re * a.re + a.im * a.im);
}
Complex exp(const Complex& a) {
Complex result;
result.re = expf(a.re) * cosf(a.im);
result.im = expf(a.re) * sinf(a.im);
return result;
}
Complex sin(const Complex& a) {
Complex result;
result.re = sinf(a.re) * coshf(a.im);
result.im = cosf(a.re) * sinhf(a.im);
return result;
}
Complex cos(const Complex& a) {
Complex result;
result.re = cosf(a.re) * coshf(a.im);
result.im = sinf(a.re) * sinhf(a.im);
return result;
}

View file

@ -0,0 +1,56 @@
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include "complex.h"
using namespace std;
// В этой программе мы рисуем в картинку комплексную функцию,
// которая задаётся в функции func
struct Color {
unsigned char r, g, b;
};
Complex func(Complex z) {
Complex f = 100/(z - 1)*exp(z);
f.re = fabs(f.re);
f.im = fabs(f.im);
if (f.re > 255)
f.re = 255;
if (f.im > 255)
f.im = 255;
return f;
}
int main() {
int width = 800, height = 800;
float x0 = -2.0f, x1 = 2.0f;
float y0 = -2.0f, y1 = 2.0f;
// Выделяем память под пиксели
Color* data = (Color*)malloc(sizeof(Color) * width * height);
// data - это массив цветов размером width * height
// Задаём значения этого массива так, чтобы
// реальная часть функции func соответствовала зелёному цвету,
// а мнимая часть -- синей компоненте цвета
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
Complex z = {x0 + (x1-x0) / width * i, y0 + (y1-y0) / width * j};
Complex f = func(z);
data[i + width * j].r = 0;
data[i + width * j].g = f.re;
data[i + width * j].b = f.im;
}
}
// Сохраняем массив цветов data как картинку в формате .ppm
FILE* file = fopen("complex_image.ppm", "wb");
fprintf(file, "P6\n%d %d\n255\n", width, height);
fwrite(data, sizeof(Color), height * width, file);
fclose(file);
// Освобождаем память
free(data);
}

View file

@ -0,0 +1,63 @@
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include "complex.h"
using namespace std;
// Это программа создаёт анимацию (набор картинок)
// которая задаётся как меняющееся во времени
// комплексная функция (описана в функции func)
struct Color {
unsigned char r, g, b;
};
Complex func(Complex z, int time) {
Complex f = 100/(z - (0.02f*time))*exp(z*sin(z));
f.re = fabs(f.re);
f.im = fabs(f.im);
if (f.re > 255)
f.re = 255;
if (f.im > 255)
f.im = 255;
return f;
}
int main() {
int width = 800, height = 800;
float x0 = -2.0f, x1 = 2.0f;
float y0 = -2.0f, y1 = 2.0f;
Color* data = (Color*)malloc(sizeof(Color) * width * height);
// Повторяем 200 раз
int max_time_steps = 200;
for (int time = 0; time < max_time_steps; time++)
{
// Задаём изображение в массиве data
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
Complex z = {x0 + (x1-x0) / width * i, y0 + (y1-y0) / width * j};
Complex f = func(z, time);
data[i + width * j].r = 0;
data[i + width * j].g = f.re;
data[i + width * j].b = f.im;
}
}
// Создаём в строке filename имя изображения
// Папка animation должна существовать!
char filename[100];
sprintf(filename, "animation/complex_%03d.ppm", time);
// Сохраняем изображение в картинке по имени filename
FILE* file = fopen(filename, "wb");
fprintf(file, "P6\n%d %d\n255\n", width, height);
fwrite(data, sizeof(Color), height * width, file);
fclose(file);
}
free(data);
}

View file

@ -0,0 +1,38 @@
#include <iostream>
#include "complex.h"
using namespace std;
// Тут мы тестируем нашу реализацию комплексных чисел
int main() {
Complex a;
Complex b;
cin >> a >> b;
cout << "a = " << a << endl
<< "b = " << b << endl
<< "a + b = " << a + b << endl
<< "a - b = " << a - b << endl
<< "a * b = " << a * b << endl
<< "a / b = " << a / b << endl
<< "-a = " << -a << endl
<< "+a = " << +a << endl
<< "*a = " << *a << endl
<< "a + 5 = " << a + 5 << endl
<< "5 + a = " << 5 + a << endl
<< "a * 5 = " << a * 5 << endl
<< "5 * a = " << 5 * a << endl
<< "Exp(a) = " << exp(a) << endl
<< "Sin(a) = " << sin(a) << endl
<< "Cos(a) = " << cos(a) << endl
<< "Exp((a + b) / a) * Cos(a - b) = " << exp((a + b) / a) * cos(a - b) << endl;
a += b;
cout << "a += b; a = " << a << endl;
// Оператор = мы не перегружали, но это всё равно работает
b = a;
cout << "b = a; b = " << b << endl;
}

Binary file not shown.

View file

@ -0,0 +1,160 @@
\documentclass{article}
\usepackage[utf8x]{inputenc}
\usepackage{ucs}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{marvosym}
\usepackage{wasysym}
\usepackage{upgreek}
\usepackage[english,russian]{babel}
\usepackage{graphicx}
\usepackage{float}
\usepackage{textcomp}
\usepackage{hyperref}
\usepackage{geometry}
\geometry{left=2cm}
\geometry{right=1.5cm}
\geometry{top=1cm}
\geometry{bottom=2cm}
\usepackage{tikz}
\usepackage{ccaption}
\usepackage{multicol}
\usepackage{listings}
%\setlength{\columnsep}{1.5cm}
%\setlength{\columnseprule}{0.2pt}
\usepackage{colortbl,graphicx,tikz}
\definecolor{X}{rgb}{.5,.5,.5}
\title{ДЗ. Работа с изображениями в формате \texttt{.ppm}}
\date{}
\begin{document}
\pagenumbering{gobble}
\lstset{
language=C++, % choose the language of the code
basicstyle=\linespread{1.1}\ttfamily,
columns=fixed,
fontadjust=true,
basewidth=0.5em,
keywordstyle=\color{blue}\bfseries,
commentstyle=\color{gray},
stringstyle=\ttfamily\color{orange!50!black},
showstringspaces=false,
%numbers=false, % where to put the line-numbers
numbersep=5pt,
numberstyle=\tiny\color{black},
numberfirstline=true,
stepnumber=1, % the step between two line-numbers.
numbersep=10pt, % how far the line-numbers are from the code
backgroundcolor=\color{white}, % choose the background color. You must add \usepackage{color}
showstringspaces=false, % underline spaces within strings
captionpos=b, % sets the caption-position to bottom
breaklines=true, % sets automatic line breaking
breakatwhitespace=true, % sets if automatic breaks should only happen at whitespace
xleftmargin=.2in,
extendedchars=\true,
keepspaces = true,
}
\lstset{literate=%
*{0}{{{\color{red!20!violet}0}}}1
{1}{{{\color{red!20!violet}1}}}1
{2}{{{\color{red!20!violet}2}}}1
{3}{{{\color{red!20!violet}3}}}1
{4}{{{\color{red!20!violet}4}}}1
{5}{{{\color{red!20!violet}5}}}1
{6}{{{\color{red!20!violet}6}}}1
{7}{{{\color{red!20!violet}7}}}1
{8}{{{\color{red!20!violet}8}}}1
{9}{{{\color{red!20!violet}9}}}1
}
\title{Семинар \#1: Ссылки и перегрузка операторов. Домашнее задание.\vspace{-5ex}}\date{}\maketitle
\subsection*{Пространство имён:}
\begin{itemize}
\item Создайте пространство имён по имени \texttt{myspace}. В этом пространстве имён создайте функцию \\
\texttt{void print\_n\_times(char str[], int n = 10)}, которая будет печатать строку \texttt{str} \texttt{n} раз. Для печати используйте \texttt{std::cout} из библиотеки \texttt{iostream}. Вызовите эту функцию из \texttt{main}.
\end{itemize}
\subsection*{Ссылки:}
\begin{itemize}
\item Напишите функцию \texttt{cube}, которая будет принимать одно число типа \texttt{int} и возводить его в куб. Используйте ссылки. Вызовите эту функцию из функции \texttt{main}.
\item Напишите функцию \texttt{void count\_letters(char str[], int\& n\_letters, int\& n\_digits, int\& n\_other)}, которая будет принимать на вход строку \texttt{str} и подсчитывать число букв и цифр в этой строке. Количество букв нужно записать в переменную \texttt{n\_letters}, количество цифр -- в переменную \texttt{n\_digits}, а количество остальных символов -- в переменную \texttt{n\_other}. Вызвать эту функцию из функции \texttt{main}.
\end{itemize}
\subsection*{Перегрузка операций:}
В файлах \texttt{code/complex.h} и \texttt{code/complex.cpp} лежит реализация комплексного числа с перегруженными операторами. Используйте его в качестве примера для решения задач этого раздела:
\begin{itemize}
\item Создайте структуру \texttt{Vector3f} - вектор в трёхмерном пространстве с полями \texttt{x, y, z} типа \texttt{float} в качестве координат. Перегрузите следующие операторы для работы с вектором. Для передачи вектора в функции используте ссылки и, там где возможно, модификатор \texttt{const}.
\begin{itemize}
\item Сложение векторов (\texttt{+})
\item Вычитание (\texttt{-})
\item Умножение вектора на число типа \texttt{float} (число \texttt{*} вектор и вектор \texttt{*} число)
\item Деление вектора на число типа \texttt{float} (вектор \texttt{/} число)
\item Скалярное произведение (\texttt{*})
\item Унарный \texttt{-}
\item Унарный \texttt{+}
\item Проверка на равенство \texttt{==} (должна возвращать тип \texttt{bool})
\item Проверка на неравенство \texttt{!=} (должна возвращать тип \texttt{bool})
\item Операторы \texttt{+=} и \texttt{-=} (вектор \texttt{+=} вектор)
\item Операторы \texttt{*=} и \texttt{/=} (вектор \texttt{*=} число)
\item Оператор вывода \texttt{ostream >{}>} вектор. Выводите вектор в виде \texttt{(x, y, z)}.
\item Оператор ввода \texttt{istream <{}<} вектор
\item Функция \texttt{float squared\_norm(const Vector3f\& a)}, которая вычисляет квадрат нормы вектора.
\item Функция \texttt{float norm(const Vector3f\& a)}, которая вычисляет норму вектора.
\item Функция \texttt{void normalize(Vector3f\& a)}, которая нормализует вектор \texttt{a}.
\end{itemize}
\item Поместите весь ваш код в отдельный файл \texttt{vector3f.h} и подключите к файлу \texttt{main.cpp}.
\item Протестируйте ваши функции:
\begin{lstlisting}
#include <iostream>
#include "vector3f.h"
using namespace std;
int main() {
Vector3f a = {1.0, 2.0, -2.0};
Vector3f b = {4.0, -1.0, 3.0};
cout << "a = " << a << endl << "b = " << b << endl;
cout << "a + b = " << a + b << endl;
cout << "-a = " << -a << endl;
cout << "Scalar product of a and b = " << a * b << endl;
a /= 5;
cout << "a after a /= 5;" << a << endl
normalize(b);
cout << "Normalized b:" << b << endl
a += b;
cout << "a after a+= b;" << a << endl;
}
\end{lstlisting}
\end{itemize}
\subsection*{Задача об убегающей точке}
\begin{itemize}
\item Предположим, что у нас есть комплексная функция $f(z) = z^2$. Выберем некоторое комплексное число $z_0$ и будем проводить следующие итерации:
\begin{equation}
\label{fractalseq}
z_1 = f(z_0)\quad z_2 = f(z_1)\quad ...\quad z_{k+1} = f(z_k)\quad ...
\end{equation}
В зависимости от выбора точки $z_0$ эта последовательность либо разойдётся, либо останется в некоторой ограниченной области. Будем называть точку $z_0$ убегающей, если $z_k \rightarrow \infty$ при $k \rightarrow \infty$. Найдите область неубегания для функции $z^2$, т.е. множество всех начальных значений $z_0$, при которых последовательность (\ref{fractalseq}) остаётся ограниченной (это можно сделать в уме). \\
\item \textbf{Julia:} Для функции $f(z) = z^2$ эта область тривиальна, но всё становится сложней для функции вида $f(z) = z^2 + c$, где $c$ -- некоторое комплексное число. Численно найдите область неубегания для функций такого вида. Для этого создайте изображение размера 800x800, покрывающую область \texttt{[-2:2]x[-2:2]} на комплексной плоскости. Для каждой точки этой плоскости проведите $N \approx 20$ итераций и, в зависимости от результата, окрасьте пиксель в соответствующий цвет (цвет можно подобрать самим, он должен быть пропорционален значению $z_N$ - меняться от яркого если $z_N$ мало и до черного если $z_N$ большое). Используйте класс Complex и перегруженные операторы. Пример работы с изображениями в формате \texttt{ppm} можно посмотреть в файле \texttt{complex\_image.cpp}. Программа должна создавать файл \texttt{julia.ppm}.
\begin{center}
\includegraphics[scale=0.7]{../images/complexplane.png}
\end{center}
\item Нарисуте изображение для $c = -0.4 + 0.6i$;\quad $c = -0.70 - 0.38i$;\quad $c = -0.80 + 0.16i$\quad и\quad $c = 0.280 + 0.011i$.
\item Добавьте параметры командной строки: 2 вещественных числа, соответствующие комплексному числу $c$, и целое число итераций $N$.
\item \textbf{Mandelbrot:} Зафиксируем теперь $z_0 = 0$ и будем менять $c$. Численно найдите все параметры $c$, для которых точка $z_0$ не является убегающей. Для этого создайте изображение размера 800x800, покрывающую область \texttt{[-2:2]x[-2:2]} возможных значений $c$ на комплексной плоскости. Программа должна создавать файл \texttt{mandelbrot.ppm}.
\item \textbf{Анимация:} Программа \texttt{complex\_movie.cpp} создаёт множество изображений и сохраняет их в папку \texttt{animation} (если у вас нет такой папки -- создайте её). Эти изображения представляют собой отдельные кадры будущей анимации. Чтобы их объединить в одно видео можно использовать программу ffmpeg (Нужно скачать тут: \href{https://www.ffmpeg.org/}{www.ffmpeg.org} и изменить переменную среды \texttt{PATH} в настройках Windows или Linux). После этого можно будет объединить все изображения в одно видео такой командой:
\begin{verbatim}
ffmpeg -r 60 -i animation/complex_%03d.ppm complex_movie.mp4
\end{verbatim}
Создайте анимацию из изображений множеств Julia при $c$ линейно меняющемся от $(-1.5 - 0.5i)$ до $i$.
\end{itemize}
\end{document}

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View file

@ -0,0 +1,490 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg8"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="complexplane.svg"
inkscape:export-filename="C:\Users\vova\workspace\latex\cs_mipt_faki\term2\seminar01_overload\images\complexplane.png"
inkscape:export-xdpi="300"
inkscape:export-ydpi="300">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4404"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
transform="scale(0.4)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
id="path4402" />
</marker>
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0.0"
refX="0.0"
id="marker3702"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path3700"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker1848"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="TriangleOutM"
inkscape:collect="always">
<path
transform="scale(0.4)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
id="path1846" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0.0"
refX="0.0"
id="marker1755"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path1753"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8)" />
</marker>
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0.0"
refX="0.0"
id="TriangleOutM"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path962"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4)" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Mend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path844"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.6) rotate(180) translate(0,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Send"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path832"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.2) rotate(180) translate(6,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Mend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path826"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0.0"
refX="0.0"
id="TriangleOutL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path959"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8)" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend-1"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path844-7"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker1848-1"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
inkscape:connector-curvature="0"
transform="scale(0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path1846-2" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker1848-1-0"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
inkscape:connector-curvature="0"
transform="scale(0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path1846-2-9" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="353.12978"
inkscape:cy="607.47601"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="2048"
inkscape:window-height="1089"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
d="M 40.892237,140.11279 H 184.68324"
id="path815"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.44465432;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend-1)"
d="M 111.09637,191.55795 V 77.837989"
id="path815-0"
inkscape:connector-curvature="0" />
<circle
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.3160204;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1628"
cx="111.0882"
cy="140.01112"
r="0.76016355" />
<circle
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1628-8"
cx="148.20093"
cy="118.06308"
r="1.2027128" />
<circle
style="opacity:1;fill:#8c8c8c;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1628-8-7"
cx="122.00854"
cy="111.38131"
r="1.2027128" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="149.13637"
y="123.00754"
id="text1662"><tspan
sodipodi:role="line"
id="tspan1660"
x="149.13637"
y="123.00754"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Consolas;-inkscape-font-specification:Consolas;stroke-width:0.26458332">z<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:64.99999762%;font-family:Consolas;-inkscape-font-specification:Consolas;baseline-shift:sub"
id="tspan1664">0</tspan></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="117.36532"
y="107.94124"
id="text1662-1"><tspan
sodipodi:role="line"
id="tspan1660-7"
x="117.36532"
y="107.94124"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Consolas;-inkscape-font-specification:Consolas;stroke-width:0.26458332">z<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan1691">0</tspan><tspan
style="font-size:64.99999762%;baseline-shift:super"
id="tspan1693">2</tspan></tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleOutM)"
d="m 148.06731,118.19668 c -11.62623,3.07361 -18.17432,2.67269 -24.58879,-4.67721"
id="path1695"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.28318167px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker1848)"
d="m 122.80545,110.44543 7.46851,-10.603435"
id="path1823"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<circle
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1628-8-1"
cx="131.8873"
cy="97.715988"
r="1.2027128" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="132.06721"
y="94.73333"
id="text1662-2"><tspan
sodipodi:role="line"
id="tspan1660-4"
x="132.06721"
y="94.73333"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Consolas;-inkscape-font-specification:Consolas;stroke-width:0.26458332">z<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan1931">1</tspan></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="127.48359"
y="106.24847"
id="text1935"><tspan
sodipodi:role="line"
id="tspan1933"
x="127.48359"
y="106.24847"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.17499995px;font-family:Consolas;-inkscape-font-specification:Consolas;stroke-width:0.26458332">c</tspan></text>
<circle
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1628-8-1-4"
cx="83.3881"
cy="93.474258"
r="1.2027128" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="83.92263"
y="90.667931"
id="text1963"><tspan
sodipodi:role="line"
id="tspan1961"
x="83.92263"
y="90.667931"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Consolas;-inkscape-font-specification:Consolas;stroke-width:0.26458332">z<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan1965">2</tspan></tspan></text>
<circle
style="opacity:1;fill:#8c8c8c;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1628-8-7-4"
cx="73.736542"
cy="106.99813"
r="1.2027128" />
<path
style="fill:none;stroke:#000000;stroke-width:0.28318167px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker1848-1)"
d="m 74.533458,106.06225 7.46851,-10.603432"
id="path1823-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="66.792633"
y="105.14875"
id="text1662-1-8"><tspan
sodipodi:role="line"
id="tspan1660-7-8"
x="66.792633"
y="105.14875"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Consolas;-inkscape-font-specification:Consolas;stroke-width:0.26458332">z<tspan
style="font-size:65%;baseline-shift:sub"
id="tspan3362">1</tspan><tspan
style="font-size:3.21027756px;baseline-shift:super;stroke-width:0.26458332"
id="tspan1693-5">2</tspan></tspan></text>
<circle
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1628-8-1-4-5"
cx="104.43866"
cy="160.09435"
r="1.2027128" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="104.97319"
y="157.28801"
id="text1963-6"><tspan
sodipodi:role="line"
id="tspan1961-6"
x="104.97319"
y="157.28801"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Consolas;-inkscape-font-specification:Consolas;stroke-width:0.26458332">z<tspan
style="font-size:65%;baseline-shift:sub"
id="tspan3474">3</tspan></tspan></text>
<circle
style="opacity:1;fill:#8c8c8c;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1628-8-7-4-8"
cx="94.787102"
cy="173.61821"
r="1.2027128" />
<path
style="fill:none;stroke:#000000;stroke-width:0.28318167px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker1848-1-0)"
d="m 95.584015,172.68232 7.468515,-10.60343"
id="path1823-5-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="87.843193"
y="171.76883"
id="text1662-1-8-4"><tspan
sodipodi:role="line"
id="tspan1660-7-8-2"
x="87.843193"
y="171.76883"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Consolas;-inkscape-font-specification:Consolas;stroke-width:0.26458332">z<tspan
style="font-size:65%;baseline-shift:sub"
id="tspan3472">2</tspan><tspan
style="font-size:3.21027756px;baseline-shift:super;stroke-width:0.26458332"
id="tspan1693-5-9">2</tspan></tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 161.77381,138.43899 v 3.96875"
id="path3476"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="162.52975"
y="144.77008"
id="text3480"><tspan
sodipodi:role="line"
id="tspan3478"
x="162.52975"
y="144.77008"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Consolas;-inkscape-font-specification:Consolas;stroke-width:0.26458332">1</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 62.552971,138.29726 v 3.96875"
id="path3476-9"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="62.552963"
y="144.62834"
id="text3480-1"><tspan
sodipodi:role="line"
id="tspan3478-1"
x="62.552963"
y="144.62834"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Consolas;-inkscape-font-specification:Consolas;stroke-width:0.26458332">-1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="180.29465"
y="145.43155"
id="text3516"><tspan
sodipodi:role="line"
id="tspan3514"
x="180.29465"
y="145.43155"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Consolas;-inkscape-font-specification:Consolas;stroke-width:0.26458332">Re</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="114.01411"
y="78.19413"
id="text3516-5"><tspan
sodipodi:role="line"
id="tspan3514-5"
x="114.01411"
y="78.19413"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Consolas;-inkscape-font-specification:Consolas;stroke-width:0.26458332">Im</tspan></text>
<path
style="fill:none;stroke:#000002;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3702);stroke-dashoffset:0"
d="M 131.0957,96.547854 C 114.25772,93.206983 83.588544,102.82868 76.03818,106.50365"
id="path3692"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4404)"
d="M 82.185379,92.605629 C 39.819072,91.505729 40.154686,168.69649 91.71736,174.07274"
id="path4394"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB