commit 2369f801af5e2ab85d1f9ea54c7fd5b488a2f153 Author: nihonium Date: Thu Sep 1 16:37:41 2022 +0300 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c749891 --- /dev/null +++ b/.gitignore @@ -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 diff --git a/seminar01_overload/classroom_tasks/classroom_tasks_overload.pdf b/seminar01_overload/classroom_tasks/classroom_tasks_overload.pdf new file mode 100644 index 0000000..3cfca38 Binary files /dev/null and b/seminar01_overload/classroom_tasks/classroom_tasks_overload.pdf differ diff --git a/seminar01_overload/classroom_tasks/classroom_tasks_overload.tex b/seminar01_overload/classroom_tasks/classroom_tasks_overload.tex new file mode 100644 index 0000000..2bb1e48 --- /dev/null +++ b/seminar01_overload/classroom_tasks/classroom_tasks_overload.tex @@ -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 +int main() { + printf("Hello World++\n"); +} +\end{lstlisting} +Все библиотеки из языка \texttt{C} можно использовать и в языке \texttt{C++}. Только название библиотеки без \texttt{.h} на конце и с символом \texttt{c} в начале: +\begin{verbatim} + -------> +\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 +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 +// Определяем переменные, структуры, функции внутри пространства имён 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 + +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} \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/00namespace/00hello.cpp b/seminar01_overload/classroom_tasks/code/00namespace/00hello.cpp new file mode 100644 index 0000000..eef258d --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/00hello.cpp @@ -0,0 +1,33 @@ +#include + +/* + Здравствуйте, это первый файл семестра по языку 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"); +} + diff --git a/seminar01_overload/classroom_tasks/code/00namespace/01namespace.cpp b/seminar01_overload/classroom_tasks/code/00namespace/01namespace.cpp new file mode 100644 index 0000000..7b6c2b6 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/01namespace.cpp @@ -0,0 +1,48 @@ +#include + +/* + Пространства имён - 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 + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/00namespace/01namespace_solution.cpp b/seminar01_overload/classroom_tasks/code/00namespace/01namespace_solution.cpp new file mode 100644 index 0000000..b6d9059 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/01namespace_solution.cpp @@ -0,0 +1,25 @@ +#include + + +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)); +} diff --git a/seminar01_overload/classroom_tasks/code/00namespace/02struct_type_name.cpp b/seminar01_overload/classroom_tasks/code/00namespace/02struct_type_name.cpp new file mode 100644 index 0000000..f965277 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/02struct_type_name.cpp @@ -0,0 +1,24 @@ +#include + +/* + В языке 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}; +} diff --git a/seminar01_overload/classroom_tasks/code/00namespace/03namespace.cpp b/seminar01_overload/classroom_tasks/code/00namespace/03namespace.cpp new file mode 100644 index 0000000..4ece511 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/03namespace.cpp @@ -0,0 +1,40 @@ +#include + +/* + Определяем переменные/структуры/функции внутри пространства имён 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 +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/00namespace/03namespace_solution.cpp b/seminar01_overload/classroom_tasks/code/00namespace/03namespace_solution.cpp new file mode 100644 index 0000000..7c0d26f --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/03namespace_solution.cpp @@ -0,0 +1,36 @@ +#include + + +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 +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/00namespace/04name_collision.cpp b/seminar01_overload/classroom_tasks/code/00namespace/04name_collision.cpp new file mode 100644 index 0000000..e65a429 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/04name_collision.cpp @@ -0,0 +1,60 @@ +#include + +/* + Зачем вообще нужны пространства имён? + + Представьте, что вы создаёте большую программу, исходный код который + содержит миллионы строк кода. Конечно, большая часть кода написана не вами, + так как вы используете библиотеки, написанные другими программистами. + + Библиотекой можно назвать совокупность файлов исходного кода, нацеленных + на решение какой-либо задачи. Например, есть библиотека для работы с графикой + в которой содержатся функции/структуры/классы для работы с графикой. + + Если вы подключаете несколько библиотек, то существует высокая вероятность, + что название чего-либо из одной библиотеки совпадёт с названием чего-то из другой библиотеки. + Это, конечно, приведёт к ошибке. + + Чтобы этого избежать и используются пространства имён. +*/ + + + +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) Что напечатает данная программа? +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/00namespace/05using.cpp b/seminar01_overload/classroom_tasks/code/00namespace/05using.cpp new file mode 100644 index 0000000..d3833db --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/05using.cpp @@ -0,0 +1,78 @@ +#include + +/* + Если вам очень не хочется постоянно писать названия пространства имён, + то вы можете использовать ключевое слово 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; + + Приведёт ли это к ошибке и, если да, то почему? +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/00namespace/06std_cout.cpp b/seminar01_overload/classroom_tasks/code/00namespace/06std_cout.cpp new file mode 100644 index 0000000..436f140 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/06std_cout.cpp @@ -0,0 +1,65 @@ +#include + +/* + Все переменные/функции/структуры/классы стандартной библиотеки языка 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 + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/00namespace/06std_cout_solution.cpp b/seminar01_overload/classroom_tasks/code/00namespace/06std_cout_solution.cpp new file mode 100644 index 0000000..744d55c --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/06std_cout_solution.cpp @@ -0,0 +1,16 @@ +#include +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; + +} diff --git a/seminar01_overload/classroom_tasks/code/00namespace/07std_using_one_name.cpp b/seminar01_overload/classroom_tasks/code/00namespace/07std_using_one_name.cpp new file mode 100644 index 0000000..5d1277c --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/07std_using_one_name.cpp @@ -0,0 +1,32 @@ +#include + +/* + В пространстве имён 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 + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/00namespace/08std_cin.cpp b/seminar01_overload/classroom_tasks/code/00namespace/08std_cin.cpp new file mode 100644 index 0000000..9547de5 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/08std_cin.cpp @@ -0,0 +1,41 @@ +#include + +/* + Счтиывание из стандартного входа + + Рассмотрим глобальную переменную 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 есть в библиотеке + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/00namespace/08std_cin_solution.cpp b/seminar01_overload/classroom_tasks/code/00namespace/08std_cin_solution.cpp new file mode 100644 index 0000000..56b5d96 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/08std_cin_solution.cpp @@ -0,0 +1,10 @@ +#include +#include + + +int main() +{ + float a, b; + std::cin >> a >> b; + std::cout << sqrt(a * b); +} diff --git a/seminar01_overload/classroom_tasks/code/00namespace/09cprog.cpp b/seminar01_overload/classroom_tasks/code/00namespace/09cprog.cpp new file mode 100644 index 0000000..23dcdee --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/09cprog.cpp @@ -0,0 +1,42 @@ +#include +#include + +/* + Язык 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; + } + + Что теперь напечатает программа? Объясните результат. +*/ + + + diff --git a/seminar01_overload/classroom_tasks/code/00namespace/10cprog_with_std.cpp b/seminar01_overload/classroom_tasks/code/00namespace/10cprog_with_std.cpp new file mode 100644 index 0000000..675de5c --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/00namespace/10cprog_with_std.cpp @@ -0,0 +1,37 @@ +#include +#include + +/* + Желательно всё равно использовать 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; + } + + Что теперь напечатает программа? Объясните результат. +*/ + + diff --git a/seminar01_overload/classroom_tasks/code/01ref/00ref.cpp b/seminar01_overload/classroom_tasks/code/01ref/00ref.cpp new file mode 100644 index 0000000..e5ec010 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/00ref.cpp @@ -0,0 +1,60 @@ +#include +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 в квадрат + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/01ref.cpp b/seminar01_overload/classroom_tasks/code/01ref/01ref.cpp new file mode 100644 index 0000000..d1af855 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/01ref.cpp @@ -0,0 +1,39 @@ +#include +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 в конце этой программы + + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/02ref.cpp b/seminar01_overload/classroom_tasks/code/01ref/02ref.cpp new file mode 100644 index 0000000..106b64e --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/02ref.cpp @@ -0,0 +1,43 @@ +#include +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 + Напечатайте этот массив + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/03ref_pointer_diff_init.cpp b/seminar01_overload/classroom_tasks/code/01ref/03ref_pointer_diff_init.cpp new file mode 100644 index 0000000..b6142bb --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/03ref_pointer_diff_init.cpp @@ -0,0 +1,49 @@ +#include +using std::cout, std::endl; + + +/* + Несмотря на то, что ссылки и указатели во многом похожи, у них есть и много больших отличий. + (помимо разной инициализации и того, что ссылку не нужно постоянно разыменовывать) + + + Различие 1) + Указатель можно создать без инициализации вот так: + int* p; + В этом случае в p будет храниться произвольный адрес. + Разыменовывать такой указатель, не задав его значение адресом какого-либо объекта, + очень опасно, это может привести к сложновыявляемым ошибкам. + + Ссылку нельзя создать без инициализации, то есть так нельзя: + int& r; + При создании ссылки нужно указать на что она будет указывать + + + Различие 2) + Указатель можно приравнять нулевому значению + В C++ вводится специальное нулевое значение для указателя nullptr + Вместо NULL, который был просто равен числу 0. В C++ лучше использовать nullptr + Разыменование нулевого указателя также приведёт к ошибке. + + Ссылку нельзя присвоить никакому нулевому значению + +*/ + +int main() +{ + +} + + +/* + Задачи: + + 1) Попробуйте создать: + a) Указатель без инициализации + б) Ссылку без инициализации + + в) Указатель, равнуй нулевому значению nullptr + г) Ссылку, равную нулю + + Скомпилируется ли программа в этих 4-х случаях? +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/04ref_pointer_diff_assign.cpp b/seminar01_overload/classroom_tasks/code/01ref/04ref_pointer_diff_assign.cpp new file mode 100644 index 0000000..46a707a --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/04ref_pointer_diff_assign.cpp @@ -0,0 +1,52 @@ +#include +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) Запустите программу, проверьте ваши догадки и объясните результат + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/05ref_pointer_diff_arith.cpp b/seminar01_overload/classroom_tasks/code/01ref/05ref_pointer_diff_arith.cpp new file mode 100644 index 0000000..a4804a8 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/05ref_pointer_diff_arith.cpp @@ -0,0 +1,44 @@ +#include +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 в конце данной программы + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/06ref_restrictions.cpp b/seminar01_overload/classroom_tasks/code/01ref/06ref_restrictions.cpp new file mode 100644 index 0000000..5857823 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/06ref_restrictions.cpp @@ -0,0 +1,46 @@ +#include +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; + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/07func_ref.cpp b/seminar01_overload/classroom_tasks/code/01ref/07func_ref.cpp new file mode 100644 index 0000000..55ec344 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/07func_ref.cpp @@ -0,0 +1,69 @@ +#include +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) + + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/07func_ref_solution.cpp b/seminar01_overload/classroom_tasks/code/01ref/07func_ref_solution.cpp new file mode 100644 index 0000000..9fcb592 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/07func_ref_solution.cpp @@ -0,0 +1,50 @@ +#include +#include +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) + + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/08func_ref_struct.cpp b/seminar01_overload/classroom_tasks/code/01ref/08func_ref_struct.cpp new file mode 100644 index 0000000..78ae781 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/08func_ref_struct.cpp @@ -0,0 +1,81 @@ +#include +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 + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/08func_ref_struct_solution.cpp b/seminar01_overload/classroom_tasks/code/01ref/08func_ref_struct_solution.cpp new file mode 100644 index 0000000..ebfceef --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/08func_ref_struct_solution.cpp @@ -0,0 +1,41 @@ +#include +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); +} + diff --git a/seminar01_overload/classroom_tasks/code/01ref/09by_value_pointer_ref.cpp b/seminar01_overload/classroom_tasks/code/01ref/09by_value_pointer_ref.cpp new file mode 100644 index 0000000..baac9d3 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/09by_value_pointer_ref.cpp @@ -0,0 +1,73 @@ +#include +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 + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/09by_value_pointer_ref_solution.cpp b/seminar01_overload/classroom_tasks/code/01ref/09by_value_pointer_ref_solution.cpp new file mode 100644 index 0000000..899e1c7 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/09by_value_pointer_ref_solution.cpp @@ -0,0 +1,54 @@ +#include +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; + +} \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/10const_ref.cpp b/seminar01_overload/classroom_tasks/code/01ref/10const_ref.cpp new file mode 100644 index 0000000..3df3a6a --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/10const_ref.cpp @@ -0,0 +1,97 @@ +#include +#include +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) +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/10const_ref2.cpp b/seminar01_overload/classroom_tasks/code/01ref/10const_ref2.cpp new file mode 100644 index 0000000..9d1f484 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/10const_ref2.cpp @@ -0,0 +1,63 @@ +#include +#include +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); +} + + diff --git a/seminar01_overload/classroom_tasks/code/01ref/11return_ref.cpp b/seminar01_overload/classroom_tasks/code/01ref/11return_ref.cpp new file mode 100644 index 0000000..8436ff0 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/11return_ref.cpp @@ -0,0 +1,50 @@ +#include +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; +} + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/12return_ref_local.cpp b/seminar01_overload/classroom_tasks/code/01ref/12return_ref_local.cpp new file mode 100644 index 0000000..8b15dbc --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/12return_ref_local.cpp @@ -0,0 +1,51 @@ +#include +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; + } + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/13return_ref_argument.cpp b/seminar01_overload/classroom_tasks/code/01ref/13return_ref_argument.cpp new file mode 100644 index 0000000..ce7b9e3 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/13return_ref_argument.cpp @@ -0,0 +1,39 @@ +#include +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; +} + + + +/* + Что напечатает данная программа? +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/01ref/14problem_1.cpp b/seminar01_overload/classroom_tasks/code/01ref/14problem_1.cpp new file mode 100644 index 0000000..8458de8 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/14problem_1.cpp @@ -0,0 +1,17 @@ +#include +using std::cout, std::endl; + + +/* + Задача: + + Напишите функцию multiplyBy2, которая принимает число по ссылке и увеличивает его в 2 раза + Вызовите эту функцию из функции main + +*/ + +int main() +{ + +} + diff --git a/seminar01_overload/classroom_tasks/code/01ref/14problem_1_solution.cpp b/seminar01_overload/classroom_tasks/code/01ref/14problem_1_solution.cpp new file mode 100644 index 0000000..8a264b1 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/14problem_1_solution.cpp @@ -0,0 +1,16 @@ +#include +using std::cout, std::endl; + + +void multiplyBy2(int& a) +{ + a *= 2; +} + +int main() +{ + int x = 10; + multiplyBy2(x); + cout << x << endl; +} + diff --git a/seminar01_overload/classroom_tasks/code/01ref/15problem_2.cpp b/seminar01_overload/classroom_tasks/code/01ref/15problem_2.cpp new file mode 100644 index 0000000..39c5515 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/15problem_2.cpp @@ -0,0 +1,22 @@ +#include +using std::cout, std::endl; + + +/* + Задача: + + Напишите функцию sumAndSave, которая должна принимать 3 аргумента + Первые два аргумента по значению + Третий аргумент по ссылке + + Функция должна складывать первые 2 аргумента и сохранять результат по третей ссылке + + Вызовите эту функцию из функции main + +*/ + +int main() +{ + +} + diff --git a/seminar01_overload/classroom_tasks/code/01ref/15problem_2_solution.cpp b/seminar01_overload/classroom_tasks/code/01ref/15problem_2_solution.cpp new file mode 100644 index 0000000..dffaf64 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/15problem_2_solution.cpp @@ -0,0 +1,36 @@ +#include +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; +} + diff --git a/seminar01_overload/classroom_tasks/code/01ref/15problem_3.cpp b/seminar01_overload/classroom_tasks/code/01ref/15problem_3.cpp new file mode 100644 index 0000000..844c8cc --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/15problem_3.cpp @@ -0,0 +1,28 @@ +#include +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; + +} + diff --git a/seminar01_overload/classroom_tasks/code/01ref/15problem_3_solution.cpp b/seminar01_overload/classroom_tasks/code/01ref/15problem_3_solution.cpp new file mode 100644 index 0000000..7cf9e5c --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/01ref/15problem_3_solution.cpp @@ -0,0 +1,23 @@ +#include +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; +} + diff --git a/seminar01_overload/classroom_tasks/code/02function_overload/00c_functions.c b/seminar01_overload/classroom_tasks/code/02function_overload/00c_functions.c new file mode 100644 index 0000000..b478e0b --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/02function_overload/00c_functions.c @@ -0,0 +1,61 @@ +#include + +/* + Это программа на языке 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? + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/02function_overload/01cpp_functions.cpp b/seminar01_overload/classroom_tasks/code/02function_overload/01cpp_functions.cpp new file mode 100644 index 0000000..ecd9016 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/02function_overload/01cpp_functions.cpp @@ -0,0 +1,66 @@ +#include +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 + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/02function_overload/02problem.cpp b/seminar01_overload/classroom_tasks/code/02function_overload/02problem.cpp new file mode 100644 index 0000000..a748b3d --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/02function_overload/02problem.cpp @@ -0,0 +1,30 @@ +#include +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 -- неправильно +} \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/02function_overload/02problem_solution.cpp b/seminar01_overload/classroom_tasks/code/02function_overload/02problem_solution.cpp new file mode 100644 index 0000000..26ae5aa --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/02function_overload/02problem_solution.cpp @@ -0,0 +1,53 @@ +#include +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; +} \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/02function_overload/03problem.cpp b/seminar01_overload/classroom_tasks/code/02function_overload/03problem.cpp new file mode 100644 index 0000000..740f833 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/02function_overload/03problem.cpp @@ -0,0 +1,42 @@ +#include +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); +} \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/02function_overload/03problem_solution.cpp b/seminar01_overload/classroom_tasks/code/02function_overload/03problem_solution.cpp new file mode 100644 index 0000000..a8e3098 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/02function_overload/03problem_solution.cpp @@ -0,0 +1,66 @@ +#include +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); +} \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/02function_overload/04std.cpp b/seminar01_overload/classroom_tasks/code/02function_overload/04std.cpp new file mode 100644 index 0000000..136311a --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/02function_overload/04std.cpp @@ -0,0 +1,17 @@ +#include +#include +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; +} \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/02function_overload/05ref_overload.cpp b/seminar01_overload/classroom_tasks/code/02function_overload/05ref_overload.cpp new file mode 100644 index 0000000..65c2f55 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/02function_overload/05ref_overload.cpp @@ -0,0 +1,67 @@ +#include +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; + } + + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/02function_overload/animals.cpp b/seminar01_overload/classroom_tasks/code/02function_overload/animals.cpp new file mode 100644 index 0000000..6b80feb --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/02function_overload/animals.cpp @@ -0,0 +1,30 @@ +#include +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); +} \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/03operator_overload/00no_operator_overload.cpp b/seminar01_overload/classroom_tasks/code/03operator_overload/00no_operator_overload.cpp new file mode 100644 index 0000000..923d93b --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/03operator_overload/00no_operator_overload.cpp @@ -0,0 +1,48 @@ +#include +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) + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/03operator_overload/00no_operator_overload_solution.cpp b/seminar01_overload/classroom_tasks/code/03operator_overload/00no_operator_overload_solution.cpp new file mode 100644 index 0000000..07d04d3 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/03operator_overload/00no_operator_overload_solution.cpp @@ -0,0 +1,44 @@ +#include +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; +} + diff --git a/seminar01_overload/classroom_tasks/code/03operator_overload/01_operator_overload.cpp b/seminar01_overload/classroom_tasks/code/03operator_overload/01_operator_overload.cpp new file mode 100644 index 0000000..2b7275f --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/03operator_overload/01_operator_overload.cpp @@ -0,0 +1,63 @@ +#include +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) + + + + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/03operator_overload/01_operator_overload_solution.cpp b/seminar01_overload/classroom_tasks/code/03operator_overload/01_operator_overload_solution.cpp new file mode 100644 index 0000000..1b5d7af --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/03operator_overload/01_operator_overload_solution.cpp @@ -0,0 +1,50 @@ +#include +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; + +} diff --git a/seminar01_overload/classroom_tasks/code/03operator_overload/02_operator_unary.cpp b/seminar01_overload/classroom_tasks/code/03operator_overload/02_operator_unary.cpp new file mode 100644 index 0000000..2c8dac3 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/03operator_overload/02_operator_unary.cpp @@ -0,0 +1,71 @@ +#include +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) + + + + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/03operator_overload/03bool.cpp b/seminar01_overload/classroom_tasks/code/03operator_overload/03bool.cpp new file mode 100644 index 0000000..3925c8f --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/03operator_overload/03bool.cpp @@ -0,0 +1,38 @@ +#include +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; +} + + diff --git a/seminar01_overload/classroom_tasks/code/03operator_overload/04_comparison_operators.cpp b/seminar01_overload/classroom_tasks/code/03operator_overload/04_comparison_operators.cpp new file mode 100644 index 0000000..6d8204a --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/03operator_overload/04_comparison_operators.cpp @@ -0,0 +1,68 @@ +#include +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 друг с другом + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/03operator_overload/04_comparison_operators_solution.cpp b/seminar01_overload/classroom_tasks/code/03operator_overload/04_comparison_operators_solution.cpp new file mode 100644 index 0000000..d0d2431 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/03operator_overload/04_comparison_operators_solution.cpp @@ -0,0 +1,110 @@ +#include +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. Это и приводит к ошибке. +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/03operator_overload/05iostream_overload.cpp b/seminar01_overload/classroom_tasks/code/03operator_overload/05iostream_overload.cpp new file mode 100644 index 0000000..05fd9eb --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/03operator_overload/05iostream_overload.cpp @@ -0,0 +1,49 @@ +#include +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; выдаёт ошибку в данной программе. + + Из-за чего это происходит и как исправить эту ошибку? + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/03operator_overload/05iostream_overload_solution.cpp b/seminar01_overload/classroom_tasks/code/03operator_overload/05iostream_overload_solution.cpp new file mode 100644 index 0000000..c035ba0 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/03operator_overload/05iostream_overload_solution.cpp @@ -0,0 +1,63 @@ +#include +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 по ссылке. + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/03operator_overload/06operator_overload.cpp b/seminar01_overload/classroom_tasks/code/03operator_overload/06operator_overload.cpp new file mode 100644 index 0000000..bdfcbfe --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/03operator_overload/06operator_overload.cpp @@ -0,0 +1,52 @@ +#include +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; + */ diff --git a/seminar01_overload/classroom_tasks/code/03operator_overload/setw.cpp b/seminar01_overload/classroom_tasks/code/03operator_overload/setw.cpp new file mode 100644 index 0000000..27afe6a --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/03operator_overload/setw.cpp @@ -0,0 +1,52 @@ +#include +#include +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; +} + + diff --git a/seminar01_overload/classroom_tasks/code/04other/00pointer_cast.cpp b/seminar01_overload/classroom_tasks/code/04other/00pointer_cast.cpp new file mode 100644 index 0000000..8d17b7a --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/04other/00pointer_cast.cpp @@ -0,0 +1,52 @@ +#include +#include +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)); +} + + + + +/* + + Задача: + + Исправьте ошибки компиляции, явно приведя указатель к правильным типам. + +*/ \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/04other/00pointer_cast_solution1.cpp b/seminar01_overload/classroom_tasks/code/04other/00pointer_cast_solution1.cpp new file mode 100644 index 0000000..af90543 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/04other/00pointer_cast_solution1.cpp @@ -0,0 +1,13 @@ +#include +#include +using std::cout, std::endl; + + +int main() +{ + int a = 10; + char* p = (char*)&a; + + + int* q = (int*)malloc(10 * sizeof(int)); +} \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/04other/00pointer_cast_solution2.cpp b/seminar01_overload/classroom_tasks/code/04other/00pointer_cast_solution2.cpp new file mode 100644 index 0000000..1ab4b63 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/04other/00pointer_cast_solution2.cpp @@ -0,0 +1,17 @@ +#include +#include +using std::cout, std::endl; + + +/* + В языке C++ желательно использовать более безопасное приведение типов static_cast +*/ + +int main() +{ + int a = 10; + char* p = static_cast(&a); + + + int* q = static_cast(malloc(10 * sizeof(int))); +} \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/04other/01nulptr.cpp b/seminar01_overload/classroom_tasks/code/04other/01nulptr.cpp new file mode 100644 index 0000000..7230ba4 --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/04other/01nulptr.cpp @@ -0,0 +1,50 @@ +#include + +/* + Новое специальное нулевое значение для указателя: 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); +} \ No newline at end of file diff --git a/seminar01_overload/classroom_tasks/code/04other/02default_arguments.cpp b/seminar01_overload/classroom_tasks/code/04other/02default_arguments.cpp new file mode 100644 index 0000000..fcbc7bc --- /dev/null +++ b/seminar01_overload/classroom_tasks/code/04other/02default_arguments.cpp @@ -0,0 +1,42 @@ +#include +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, то будет печатать всю строку в верхнем регистре +*/ \ No newline at end of file diff --git a/seminar01_overload/homework/code/complex.h b/seminar01_overload/homework/code/complex.h new file mode 100644 index 0000000..d1ea7a9 --- /dev/null +++ b/seminar01_overload/homework/code/complex.h @@ -0,0 +1,189 @@ +#pragma once +#include +#include + +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; +} \ No newline at end of file diff --git a/seminar01_overload/homework/code/complex_image.cpp b/seminar01_overload/homework/code/complex_image.cpp new file mode 100644 index 0000000..f8b6166 --- /dev/null +++ b/seminar01_overload/homework/code/complex_image.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#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); +} \ No newline at end of file diff --git a/seminar01_overload/homework/code/complex_movie.cpp b/seminar01_overload/homework/code/complex_movie.cpp new file mode 100644 index 0000000..8470887 --- /dev/null +++ b/seminar01_overload/homework/code/complex_movie.cpp @@ -0,0 +1,63 @@ +#include +#include +#include +#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); +} \ No newline at end of file diff --git a/seminar01_overload/homework/code/complex_test.cpp b/seminar01_overload/homework/code/complex_test.cpp new file mode 100644 index 0000000..6dd99c1 --- /dev/null +++ b/seminar01_overload/homework/code/complex_test.cpp @@ -0,0 +1,38 @@ +#include +#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; +} \ No newline at end of file diff --git a/seminar01_overload/homework/homework_overload.pdf b/seminar01_overload/homework/homework_overload.pdf new file mode 100644 index 0000000..f95dc88 Binary files /dev/null and b/seminar01_overload/homework/homework_overload.pdf differ diff --git a/seminar01_overload/homework/homework_overload.tex b/seminar01_overload/homework/homework_overload.tex new file mode 100644 index 0000000..74767fc --- /dev/null +++ b/seminar01_overload/homework/homework_overload.tex @@ -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 +#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} \ No newline at end of file diff --git a/seminar01_overload/images/complexplane.png b/seminar01_overload/images/complexplane.png new file mode 100644 index 0000000..729c878 Binary files /dev/null and b/seminar01_overload/images/complexplane.png differ diff --git a/seminar01_overload/images/complexplane.svg b/seminar01_overload/images/complexplane.svg new file mode 100644 index 0000000..1aa30f7 --- /dev/null +++ b/seminar01_overload/images/complexplane.svg @@ -0,0 +1,490 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + z0 + z02 + + + + z1 + c + + z2 + + + z12 + + z3 + + + z22 + + 1 + + -1 + Re + Im + + + +