seminar2
This commit is contained in:
		
							parent
							
								
									46d1c64684
								
							
						
					
					
						commit
						ab6732eded
					
				
					 98 changed files with 10319 additions and 0 deletions
				
			
		|  | @ -0,0 +1,62 @@ | |||
| /*
 | ||||
|     Раздельная компиляция. | ||||
| 
 | ||||
|     В этой части мы вынесем весь код, связанный с нашим классом Point в отдельные файлы. | ||||
|     А также скомпилируем отдельно код, относящийся к нашему классу Point. | ||||
| 
 | ||||
|     Это будет проделано в следующий примерах, а пока тут просто лежит код | ||||
|     класса Point из предыдущих частей. | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <cmath> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| struct Point  | ||||
| { | ||||
|     float x, y; | ||||
| 
 | ||||
|     Point operator+(Point b) const | ||||
|     { | ||||
|         Point result = {x + b.x, y + b.y}; | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     float norm() const | ||||
|     { | ||||
|         return std::sqrt(x * x + y * y); | ||||
|     } | ||||
| 
 | ||||
|     Point operator*(float k) const | ||||
|     { | ||||
|         Point result = {k * x, k * y}; | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     void normalize() | ||||
|     { | ||||
|         float normv = norm(); | ||||
|         x /= normv; | ||||
|         y /= normv; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Point a) | ||||
| { | ||||
|     out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")"; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Point a = {7.2, 3.1}; | ||||
|     cout << a.norm() << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,81 @@ | |||
| /*
 | ||||
|     Вынос определений методов вне класса. | ||||
| 
 | ||||
|     Методы внутри класса можно только объявить, а определить их можно вне класса. | ||||
|     Например, метод norm объявлен внутри класса: | ||||
| 
 | ||||
|         float norm() const; | ||||
| 
 | ||||
|     а определён вне класса: | ||||
| 
 | ||||
|         float Point::norm() const | ||||
|         { | ||||
|             return std::sqrt(x * x + y * y); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|     Чтобы компилятор понимал к какому классу относится тот или иной метод, | ||||
|     к его имени вне класса нужно добавить название класса и два двоеточия. | ||||
|     Поэтому метод norm вне класса Point называется как Point::norm. | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <cmath> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| struct Point  | ||||
| { | ||||
|     float x, y; | ||||
| 
 | ||||
|     Point operator+(Point b) const; | ||||
|     float norm() const; | ||||
|     Point operator*(float k) const; | ||||
|     void normalize(); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| Point Point::operator+(Point b) const | ||||
| { | ||||
|     Point result = {x + b.x, y + b.y}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| float Point::norm() const | ||||
| { | ||||
|     return std::sqrt(x * x + y * y); | ||||
| } | ||||
| 
 | ||||
| Point Point::operator*(float k) const | ||||
| { | ||||
|     Point result = {k * x, k * y}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| void Point::normalize() | ||||
| { | ||||
|     float normv = norm(); | ||||
|     x /= normv; | ||||
|     y /= normv; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Point a) | ||||
| { | ||||
|     out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")"; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Point a = {7.2, 3.1}; | ||||
|     cout << a.norm() << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,61 @@ | |||
| /*
 | ||||
|     Перенос кода в заголовочный файл | ||||
| 
 | ||||
|     В этом примере мы перенесли весь код, связанный с классом Point в отдельный файл point.hpp. | ||||
|     Файл point.hpp подключается к файлу main.cpp с помощью директивы #include в строке: | ||||
| 
 | ||||
|         #include "point.hpp" | ||||
| 
 | ||||
|     На самом деле директива #include делает очень простую вещь: она просто берёт всё содержимое | ||||
|     передаваемого ей файла и вставляет это содержимое на место директивы. | ||||
|     То есть в этом примере за место  #include "point.hpp"  подставится всё содержимое файла point.hpp. | ||||
| 
 | ||||
|     Так как директива #include уже сама вставила файл point.hpp в файл main.cpp, то дополнительно | ||||
|     указывать файл point.hpp при компиляции не нужно. Скомпилировать этот пример можно так: | ||||
| 
 | ||||
|         g++ main.cpp | ||||
| 
 | ||||
| 
 | ||||
|     Стандартные библиотеки типа iostream подключаются так же. То есть где-то в системе, в какой-то папке  | ||||
|     хранится стандартная библиотека C++ и, соответственно, есть файл под название iostream (без расширения). | ||||
|     Этот файл и подставляется за место строки  #include <iostream>. | ||||
|     Чтобы посмотреть в каких папках компилятор ищет файлы стандартной библиотеки можно скомпилировать программу так: | ||||
|          | ||||
|         g++ -v main.cpp | ||||
| 
 | ||||
|     Он напечатает множество информации о компиляции, в числе прочего пути где происходит поиск при исполнении #include. | ||||
|     Вы могли заметить, что стандартные библиотеки в директиве #include пишутся в треугольных скобочках, а нашу | ||||
|     библиотеку point.hpp мы написали в двойных кавычках. В чём разница между этими вариантами? | ||||
|     На самом деле разница лишь в том, в каких папках компилятор ищет данные файлы. | ||||
|     Если мы пишем библиотеку в треугольных скобках, то компилятор ищет её в папках стандартной библиотеки. | ||||
|     Если мы пишем библиотеку в кавычках, то компилятор ищет её в папках текущей директории. | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     Защита от двойного включения | ||||
| 
 | ||||
|     Используя директивы #include, очень легко включить один и тот же файл 2 и более раз. | ||||
|     Например, в этом примере файл iostream включается 2 раза: один раз непосредственно в файле main.cpp, а второй раз  | ||||
|     он включится после того, как включиться файл point.hpp. Внутри файла point.hpp тоже есть #include <iostream>. | ||||
|     Если не предпринимать никаких действий, то произойдёт ошибка, так как одинаковые функции и классы  | ||||
|     будут повторяться в программе несколько раз. | ||||
| 
 | ||||
|     Чтобы защититься от этой проблемы нужно в начале заголовочного файла написать директиву | ||||
| 
 | ||||
|         #pragma once | ||||
| 
 | ||||
|     Таким образом компилятор будет понимать, что вы не хотите включать файл более одного раза и включит только одну копию файла. | ||||
|     Эта директива была использовани и в файле point.hpp. | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include "point.hpp" | ||||
| 
 | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Point a = {7.2, 3.1}; | ||||
|     cout << a.norm() << endl; | ||||
| } | ||||
|  | @ -0,0 +1,39 @@ | |||
| #pragma once | ||||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <cmath> | ||||
| 
 | ||||
| struct Point  | ||||
| { | ||||
|     float x, y; | ||||
| 
 | ||||
|     Point operator+(Point b) const | ||||
|     { | ||||
|         Point result = {x + b.x, y + b.y}; | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     float norm() const | ||||
|     { | ||||
|         return std::sqrt(x * x + y * y); | ||||
|     } | ||||
| 
 | ||||
|     Point operator*(float k) const | ||||
|     { | ||||
|         Point result = {k * x, k * y}; | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     void normalize() | ||||
|     { | ||||
|         float normv = norm(); | ||||
|         x /= normv; | ||||
|         y /= normv; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Point a) | ||||
| { | ||||
|     out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")"; | ||||
|     return out; | ||||
| } | ||||
|  | @ -0,0 +1,17 @@ | |||
| /*
 | ||||
|     Всё что относится к классу Point мы перенесли в отдельный файл point.hpp. | ||||
|     А также мы разделили объявления и определения методов в файле point.hpp. | ||||
| */ | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <cmath> | ||||
| #include "point.hpp" | ||||
| 
 | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Point a = {7.2, 3.1}; | ||||
|     cout << a.norm() << endl; | ||||
| } | ||||
|  | @ -0,0 +1,45 @@ | |||
| #pragma once | ||||
| #include <iostream> | ||||
| 
 | ||||
| 
 | ||||
| struct Point  | ||||
| { | ||||
|     float x, y; | ||||
| 
 | ||||
|     Point operator+(Point b) const; | ||||
|     float norm() const; | ||||
|     Point operator*(float k) const; | ||||
|     void normalize(); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| Point Point::operator+(Point b) const | ||||
| { | ||||
|     Point result = {x + b.x, y + b.y}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| float Point::norm() const | ||||
| { | ||||
|     return std::sqrt(x * x + y * y); | ||||
| } | ||||
| 
 | ||||
| Point Point::operator*(float k) const | ||||
| { | ||||
|     Point result = {k * x, k * y}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| void Point::normalize() | ||||
| { | ||||
|     float normv = norm(); | ||||
|     x /= normv; | ||||
|     y /= normv; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Point a) | ||||
| { | ||||
|     out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")"; | ||||
|     return out; | ||||
| } | ||||
|  | @ -0,0 +1,40 @@ | |||
| /*
 | ||||
|     Раздельная компиляция | ||||
| 
 | ||||
|     Теперь мы разделим объявления и определения всех методов класса Point. | ||||
|     Все объявления класса Point поместим в файл point.hpp, а определения методов в файл point.cpp. | ||||
|     Таким образом у нас получилось 2 компилируемых файла: main.cpp и point.cpp и 1 заголовочный файл point.hpp. | ||||
| 
 | ||||
|     При этом заголовочный файл point.hpp должен подключаться везде, где используется класс Point. | ||||
|     То есть в данном случае он должен подключаться и в файл main.cpp и в файл point.cpp. | ||||
|      | ||||
| 
 | ||||
|     Для компиляции программы нужно указать компилятору на все компилируемые файлы вот так: | ||||
| 
 | ||||
|         g++ main.cpp point.cpp | ||||
| 
 | ||||
|     Если это не сделать и скомпилировать только файл main.cpp, то возникнет ошибка undefined reference to norm(). | ||||
|     Грубо говоря программа будет знать, что есть класс Point и знать его методы (так как это всё описано в point.hpp),  | ||||
|     но любые попытки вызвать эти методы будут приводить к ошибке, так как они не были скомпилированы. | ||||
| 
 | ||||
| 
 | ||||
|     Преемущество раздельной компиляции заключается в том, что компилировать разные .cpp файлы можно поотдельности. | ||||
|     Представьте, что у вас огромный проект, содержащий тысячи файлов и миллионы строк кода. Такой проект может компилироваться часами. | ||||
|     Теперь вы сделали небольшое изменение в одном файле этого проекта. Если бы нельзя было бы компилировать файлы поотдельности, | ||||
|     то после любого изменения вам бы пришлось компилировать весь проект заново и ждать часы пока компиляция закончится. | ||||
|     К счастью, .cpp файлы можно компилировать поотдельности и, если вы сделали изменение в одном файле, то скомпилировать | ||||
|     потребуется только тот файл, который вы изменили. | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include "point.hpp" | ||||
| 
 | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Point a = {7.2, 3.1}; | ||||
|     cout << a.norm() << endl; | ||||
| } | ||||
|  | @ -0,0 +1,35 @@ | |||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <cmath> | ||||
| #include "point.hpp" | ||||
| 
 | ||||
| Point Point::operator+(Point b) const | ||||
| { | ||||
|     Point result = {x + b.x, y + b.y}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| float Point::norm() const | ||||
| { | ||||
|     return std::sqrt(x * x + y * y); | ||||
| } | ||||
| 
 | ||||
| Point Point::operator*(float k) const | ||||
| { | ||||
|     Point result = {k * x, k * y}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| void Point::normalize() | ||||
| { | ||||
|     float normv = norm(); | ||||
|     x /= normv; | ||||
|     y /= normv; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Point a) | ||||
| { | ||||
|     out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")"; | ||||
|     return out; | ||||
| } | ||||
|  | @ -0,0 +1,15 @@ | |||
| #pragma once | ||||
| #include <iostream> | ||||
| 
 | ||||
| 
 | ||||
| struct Point  | ||||
| { | ||||
|     float x, y; | ||||
| 
 | ||||
|     Point operator+(Point b) const; | ||||
|     float norm() const; | ||||
|     Point operator*(float k) const; | ||||
|     void normalize(); | ||||
| }; | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Point a); | ||||
|  | @ -0,0 +1,30 @@ | |||
| /*
 | ||||
|     Пространства имён | ||||
| 
 | ||||
| 
 | ||||
|     Имя Point достаточно распространённое и есть очень большая вероятность того, что при подключении нескольких библиотек | ||||
|     в некоторых из них тоже будет класс с именем Point. Конечно, если ничего не предпринять, это приведёт к ошибке. | ||||
| 
 | ||||
|     Чтобы избежать ошибок, связанных с конфликтами имён, положим весь код нашего класса Point в пространство имён mipt. | ||||
|     Для этого обернём наш код в файлах point.hpp и point.cpp | ||||
| 
 | ||||
|         namespace mipt  | ||||
|         { | ||||
|             ... | ||||
|         } | ||||
| 
 | ||||
|     Теперь наш класс Point будет лежать в пространстве имён mipt. | ||||
|     Для его использования вне пространства имён mipt нужно писать mipt::Point (ну либо использовать using mipt::Point;) | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include "point.hpp" | ||||
| 
 | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     mipt::Point a = {7.2, 3.1}; | ||||
|     cout << a.norm() << endl; | ||||
| } | ||||
|  | @ -0,0 +1,40 @@ | |||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <cmath> | ||||
| #include "point.hpp" | ||||
| 
 | ||||
| namespace mipt | ||||
| { | ||||
| 
 | ||||
| Point Point::operator+(Point b) const | ||||
| { | ||||
|     Point result = {x + b.x, y + b.y}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| float Point::norm() const | ||||
| { | ||||
|     return std::sqrt(x * x + y * y); | ||||
| } | ||||
| 
 | ||||
| Point Point::operator*(float k) const | ||||
| { | ||||
|     Point result = {k * x, k * y}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| void Point::normalize() | ||||
| { | ||||
|     float normv = norm(); | ||||
|     x /= normv; | ||||
|     y /= normv; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Point a) | ||||
| { | ||||
|     out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")"; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,20 @@ | |||
| #pragma once | ||||
| #include <iostream> | ||||
| 
 | ||||
| 
 | ||||
| namespace mipt | ||||
| { | ||||
| 
 | ||||
| struct Point  | ||||
| { | ||||
|     float x, y; | ||||
| 
 | ||||
|     Point operator+(Point b) const; | ||||
|     float norm() const; | ||||
|     Point operator*(float k) const; | ||||
|     void normalize(); | ||||
| }; | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Point a); | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,265 @@ | |||
| /*
 | ||||
|     В данной программе содержится класс String, написанный нами в одной из предыдущих частей. | ||||
| 
 | ||||
|     Задачи: | ||||
| 
 | ||||
|         1)  Вынесите класс String в отдельный заголовочный файл string.hpp и скомпилируйте программу. | ||||
| 
 | ||||
| 
 | ||||
|         2)  Вынесите объявления методов класса String в заголовочный файл string.hpp, а определения | ||||
|             методов в компилируемый файл string.cpp. Скомпилируйте программу. | ||||
| 
 | ||||
| 
 | ||||
|         3)  Вынесите объявления методов класса String в заголовочный файл string.hpp, а определения | ||||
|             методов в компилируемый файл string.cpp. А также поместите весь код класса String в пространство имён mipt. | ||||
|             Скомпилируйте программу. | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| 
 | ||||
| 
 | ||||
| class String  | ||||
| { | ||||
| private: | ||||
| 
 | ||||
|     std::size_t mSize; | ||||
|     std::size_t mCapacity; | ||||
|     char* mpData; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     String(const char* str)  | ||||
|     { | ||||
|         std::size_t i = 0; | ||||
|         while (str[i] != '\0') | ||||
|             i++; | ||||
|         mSize = i; | ||||
|         mCapacity = i + 1; | ||||
| 
 | ||||
|         mpData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
| 
 | ||||
|         for (std::size_t i = 0; str[i]; i++) | ||||
|             mpData[i] = str[i]; | ||||
|         mpData[mSize] = '\0'; | ||||
|     } | ||||
| 
 | ||||
|     String() : String("") {} | ||||
|     String(const String& s) : String(s.cStr()) {} | ||||
| 
 | ||||
|     String(std::size_t n, char a) | ||||
|     { | ||||
|         mSize = n; | ||||
|         mCapacity = n + 1; | ||||
|         mpData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
| 
 | ||||
|         for (std::size_t i = 0; i < mSize; ++i) | ||||
|             mpData[i] = a; | ||||
|         mpData[mSize] = '\0'; | ||||
|     } | ||||
| 
 | ||||
|     ~String() | ||||
|     { | ||||
|         std::free(mpData); | ||||
|     } | ||||
| 
 | ||||
|     void reserve(std::size_t capacity) | ||||
|     { | ||||
|         if (capacity <= mCapacity) | ||||
|             return; | ||||
| 
 | ||||
|         mCapacity = capacity; | ||||
|         char* newData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
| 
 | ||||
|         for (std::size_t i = 0; i < mSize; ++i) | ||||
|             newData[i] = mpData[i]; | ||||
|         newData[mSize] = '\0'; | ||||
| 
 | ||||
|         std::free(mpData); | ||||
|         mpData = newData; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void resize(std::size_t size) | ||||
|     { | ||||
|         reserve(size + 1); | ||||
|         mSize = size; | ||||
|         mpData[mSize] = '\0'; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     String& operator=(const String& right) | ||||
|     { | ||||
|         if (this == &right) | ||||
|             return *this; | ||||
| 
 | ||||
|         mSize = right.mSize; | ||||
|         resize(mSize); | ||||
| 
 | ||||
|         for (std::size_t i = 0; i <= mSize; ++i) | ||||
|             mpData[i] = right.mpData[i]; | ||||
| 
 | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     String operator+(const String& b) | ||||
|     { | ||||
|         String result; | ||||
|         result.resize(mSize + b.mSize); | ||||
| 
 | ||||
|         for (std::size_t i = 0; i < mSize; ++i) | ||||
|             result.mpData[i] = mpData[i]; | ||||
| 
 | ||||
|         for (std::size_t i = 0; i < b.mSize; ++i) | ||||
|             result.mpData[mSize + i] = b.mpData[i]; | ||||
| 
 | ||||
|         result.mpData[result.mSize] = '\0'; | ||||
| 
 | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     String& operator+=(const String& right) | ||||
|     { | ||||
|         *this = *this + right; | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     bool operator==(const String& right) const | ||||
|     { | ||||
|         if (mSize != right.mSize) | ||||
|             return false; | ||||
| 
 | ||||
|         std::size_t i = 0; | ||||
|         while (i < mSize && mpData[i] == right.mpData[i]) | ||||
|             i++; | ||||
| 
 | ||||
|         return i == mSize; | ||||
|     } | ||||
| 
 | ||||
|     bool operator<(const String& right) const | ||||
|     { | ||||
|         std::size_t i = 0; | ||||
|         while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i]) | ||||
|             i++; | ||||
| 
 | ||||
|         return mpData[i] < right.mpData[i]; | ||||
|     } | ||||
| 
 | ||||
|     bool operator<=(const String& right) const | ||||
|     { | ||||
|         std::size_t i = 0; | ||||
|         while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i]) | ||||
|             i++; | ||||
| 
 | ||||
|         return mpData[i] <= right.mpData[i]; | ||||
|     } | ||||
| 
 | ||||
|     bool operator!=(const String& right) const | ||||
|     { | ||||
|         return !(*this == right); | ||||
|     } | ||||
| 
 | ||||
|     bool operator>(const String& right) const | ||||
|     { | ||||
|         return !(*this <= right); | ||||
|     } | ||||
| 
 | ||||
|     bool operator>=(const String& right) const | ||||
|     { | ||||
|         return !(*this < right); | ||||
|     } | ||||
| 
 | ||||
|     char& operator[](std::size_t i) | ||||
|     { | ||||
|         return mpData[i]; | ||||
|     } | ||||
| 
 | ||||
|     char& at(std::size_t i) | ||||
|     { | ||||
|         if (i >= mSize) | ||||
|         { | ||||
|             std::cout << "Error! Index is out of bounds." << std::endl; | ||||
|             std::exit(1); | ||||
|         } | ||||
|         return mpData[i]; | ||||
|     } | ||||
| 
 | ||||
|     void clear() | ||||
|     { | ||||
|         std::free(mpData); | ||||
| 
 | ||||
|         mSize = 0; | ||||
|         mCapacity = 1; | ||||
|         mpData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
|         mpData[0] = '\0'; | ||||
|     } | ||||
| 
 | ||||
|     void addCharacter(char c) | ||||
|     { | ||||
|         if (mSize + 1 == mCapacity) | ||||
|             reserve(2 * mCapacity); | ||||
| 
 | ||||
|         mpData[mSize] = c; | ||||
|         resize(mSize + 1); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     std::size_t getSize()        const   {return mSize;} | ||||
|     std::size_t getCapacity()    const   {return mCapacity;} | ||||
|     const char* cStr()      const   {return mpData;} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, const String& s)  | ||||
| { | ||||
|     out << s.cStr(); | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| std::istream& operator>>(std::istream& in, String& s)  | ||||
| { | ||||
|     s.clear(); | ||||
|     while (true) | ||||
|     { | ||||
|         char x = in.get(); | ||||
|         if (x == ' ' || x == '\n' || x == '\t') | ||||
|             break; | ||||
|         s.addCharacter(x); | ||||
|     } | ||||
|     return in; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     String a = "Mouse"; | ||||
|     String b; | ||||
|     std::cin >> b; | ||||
|     String c = b; | ||||
| 
 | ||||
|     if (a + c == "MouseLion") | ||||
|         std::cout << "Yes" << std::endl; | ||||
|     else | ||||
|         std::cout << "No" << std::endl; | ||||
| 
 | ||||
| 
 | ||||
|     if (a > "Mice") | ||||
|         std::cout << "Yes" << std::endl; | ||||
|     else | ||||
|         std::cout << "No" << std::endl; | ||||
| 
 | ||||
| 
 | ||||
|     c[0] = 'P'; | ||||
|     std::cout << c << std::endl; | ||||
| 
 | ||||
|     c += a; | ||||
|     std::cout << c << std::endl; | ||||
| 
 | ||||
|     c = c + String(10, 'q'); | ||||
|     std::cout << c << std::endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,37 @@ | |||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| #include "string.hpp" | ||||
| 
 | ||||
| using std::cout, std::cin, std::endl; | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     String a = "Mouse"; | ||||
|     String b; | ||||
|     cin >> b; | ||||
|     String c = b; | ||||
| 
 | ||||
|     if (a + c == "MouseLion") | ||||
|         cout << "Yes" << endl; | ||||
|     else | ||||
|         cout << "No" << endl; | ||||
| 
 | ||||
| 
 | ||||
|     if (a > "Mice") | ||||
|         cout << "Yes" << endl; | ||||
|     else | ||||
|         cout << "No" << endl; | ||||
| 
 | ||||
| 
 | ||||
|     c[0] = 'P'; | ||||
|     cout << c << endl; | ||||
| 
 | ||||
|     c += a; | ||||
|     cout << c << endl; | ||||
| 
 | ||||
|     c = c + String(10, 'q'); | ||||
|     cout << c << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,214 @@ | |||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| 
 | ||||
| 
 | ||||
| class String  | ||||
| { | ||||
| private: | ||||
| 
 | ||||
|     std::size_t mSize; | ||||
|     std::size_t mCapacity; | ||||
|     char* mpData; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     String(const char* str)  | ||||
|     { | ||||
|         std::size_t i = 0; | ||||
|         while (str[i] != '\0') | ||||
|             i++; | ||||
|         mSize = i; | ||||
|         mCapacity = i + 1; | ||||
| 
 | ||||
|         mpData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
| 
 | ||||
|         for (std::size_t i = 0; str[i]; i++) | ||||
|             mpData[i] = str[i]; | ||||
|         mpData[mSize] = '\0'; | ||||
|     } | ||||
| 
 | ||||
|     String() : String("") {} | ||||
|     String(const String& s) : String(s.cStr()) {} | ||||
| 
 | ||||
|     String(std::size_t n, char a) | ||||
|     { | ||||
|         mSize = n; | ||||
|         mCapacity = n + 1; | ||||
|         mpData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
| 
 | ||||
|         for (std::size_t i = 0; i < mSize; ++i) | ||||
|             mpData[i] = a; | ||||
|         mpData[mSize] = '\0'; | ||||
|     } | ||||
| 
 | ||||
|     ~String() | ||||
|     { | ||||
|         std::free(mpData); | ||||
|     } | ||||
| 
 | ||||
|     void reserve(std::size_t capacity) | ||||
|     { | ||||
|         if (capacity <= mCapacity) | ||||
|             return; | ||||
| 
 | ||||
|         mCapacity = capacity; | ||||
|         char* newData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
| 
 | ||||
|         for (std::size_t i = 0; i < mSize; ++i) | ||||
|             newData[i] = mpData[i]; | ||||
|         newData[mSize] = '\0'; | ||||
| 
 | ||||
|         std::free(mpData); | ||||
|         mpData = newData; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void resize(std::size_t size) | ||||
|     { | ||||
|         reserve(size + 1); | ||||
|         mSize = size; | ||||
|         mpData[mSize] = '\0'; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     String& operator=(const String& right) | ||||
|     { | ||||
|         if (this == &right) | ||||
|             return *this; | ||||
| 
 | ||||
|         mSize = right.mSize; | ||||
|         resize(mSize); | ||||
| 
 | ||||
|         for (std::size_t i = 0; i <= mSize; ++i) | ||||
|             mpData[i] = right.mpData[i]; | ||||
| 
 | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     String operator+(const String& b) | ||||
|     { | ||||
|         String result; | ||||
|         result.resize(mSize + b.mSize); | ||||
| 
 | ||||
|         for (std::size_t i = 0; i < mSize; ++i) | ||||
|             result.mpData[i] = mpData[i]; | ||||
| 
 | ||||
|         for (std::size_t i = 0; i < b.mSize; ++i) | ||||
|             result.mpData[mSize + i] = b.mpData[i]; | ||||
| 
 | ||||
|         result.mpData[result.mSize] = '\0'; | ||||
| 
 | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     String& operator+=(const String& right) | ||||
|     { | ||||
|         *this = *this + right; | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     bool operator==(const String& right) const | ||||
|     { | ||||
|         if (mSize != right.mSize) | ||||
|             return false; | ||||
| 
 | ||||
|         std::size_t i = 0; | ||||
|         while (i < mSize && mpData[i] == right.mpData[i]) | ||||
|             i++; | ||||
| 
 | ||||
|         return i == mSize; | ||||
|     } | ||||
| 
 | ||||
|     bool operator<(const String& right) const | ||||
|     { | ||||
|         std::size_t i = 0; | ||||
|         while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i]) | ||||
|             i++; | ||||
| 
 | ||||
|         return mpData[i] < right.mpData[i]; | ||||
|     } | ||||
| 
 | ||||
|     bool operator<=(const String& right) const | ||||
|     { | ||||
|         std::size_t i = 0; | ||||
|         while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i]) | ||||
|             i++; | ||||
| 
 | ||||
|         return mpData[i] <= right.mpData[i]; | ||||
|     } | ||||
| 
 | ||||
|     bool operator!=(const String& right) const | ||||
|     { | ||||
|         return !(*this == right); | ||||
|     } | ||||
| 
 | ||||
|     bool operator>(const String& right) const | ||||
|     { | ||||
|         return !(*this <= right); | ||||
|     } | ||||
| 
 | ||||
|     bool operator>=(const String& right) const | ||||
|     { | ||||
|         return !(*this < right); | ||||
|     } | ||||
| 
 | ||||
|     char& operator[](std::size_t i) | ||||
|     { | ||||
|         return mpData[i]; | ||||
|     } | ||||
| 
 | ||||
|     char& at(std::size_t i) | ||||
|     { | ||||
|         if (i >= mSize) | ||||
|         { | ||||
|             std::cout << "Error! Index is out of bounds." << std::endl; | ||||
|             std::exit(1); | ||||
|         } | ||||
|         return mpData[i]; | ||||
|     } | ||||
| 
 | ||||
|     void clear() | ||||
|     { | ||||
|         std::free(mpData); | ||||
| 
 | ||||
|         mSize = 0; | ||||
|         mCapacity = 1; | ||||
|         mpData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
|         mpData[0] = '\0'; | ||||
|     } | ||||
| 
 | ||||
|     void addCharacter(char c) | ||||
|     { | ||||
|         if (mSize + 1 == mCapacity) | ||||
|             reserve(2 * mCapacity); | ||||
| 
 | ||||
|         mpData[mSize] = c; | ||||
|         resize(mSize + 1); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     std::size_t getSize()        const   {return mSize;} | ||||
|     std::size_t getCapacity()    const   {return mCapacity;} | ||||
|     const char* cStr()      const   {return mpData;} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, const String& s)  | ||||
| { | ||||
|     out << s.cStr(); | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| std::istream& operator>>(std::istream& in, String& s)  | ||||
| { | ||||
|     s.clear(); | ||||
|     while (true) | ||||
|     { | ||||
|         char x = in.get(); | ||||
|         if (x == ' ' || x == '\n' || x == '\t') | ||||
|             break; | ||||
|         s.addCharacter(x); | ||||
|     } | ||||
|     return in; | ||||
| } | ||||
|  | @ -0,0 +1,39 @@ | |||
| /*
 | ||||
|     Компиляция: | ||||
| 
 | ||||
|         g++ main.cpp string.cpp | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include "string.hpp" | ||||
| using std::cout, std::cin, std::endl; | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     String a = "Mouse"; | ||||
|     String b; | ||||
|     cin >> b; | ||||
|     String c = b; | ||||
| 
 | ||||
|     if (a + c == "MouseLion") | ||||
|         cout << "Yes" << endl; | ||||
|     else | ||||
|         cout << "No" << endl; | ||||
| 
 | ||||
| 
 | ||||
|     if (a > "Mice") | ||||
|         cout << "Yes" << endl; | ||||
|     else | ||||
|         cout << "No" << endl; | ||||
| 
 | ||||
| 
 | ||||
|     c[0] = 'P'; | ||||
|     cout << c << endl; | ||||
| 
 | ||||
|     c += a; | ||||
|     cout << c << endl; | ||||
| 
 | ||||
|     c = c + String(10, 'q'); | ||||
|     cout << c << endl; | ||||
| } | ||||
|  | @ -0,0 +1,204 @@ | |||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| #include "string.hpp" | ||||
| 
 | ||||
| 
 | ||||
| String::String(const char* str)  | ||||
| { | ||||
|     std::size_t i = 0; | ||||
|     while (str[i] != '\0') | ||||
|         i++; | ||||
|     mSize = i; | ||||
|     mCapacity = i + 1; | ||||
| 
 | ||||
|     mpData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
| 
 | ||||
|     for (std::size_t i = 0; str[i]; i++) | ||||
|         mpData[i] = str[i]; | ||||
|     mpData[mSize] = '\0'; | ||||
| } | ||||
| 
 | ||||
| String::String() : String("") {} | ||||
| String::String(const String& s) : String(s.cStr()) {} | ||||
| 
 | ||||
| String::String(std::size_t n, char a) | ||||
| { | ||||
|     mSize = n; | ||||
|     mCapacity = n + 1; | ||||
|     mpData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
| 
 | ||||
|     for (std::size_t i = 0; i < mSize; ++i) | ||||
|         mpData[i] = a; | ||||
|     mpData[mSize] = '\0'; | ||||
| } | ||||
| 
 | ||||
| String::~String() | ||||
| { | ||||
|     std::free(mpData); | ||||
| } | ||||
| 
 | ||||
| void String::reserve(std::size_t capacity) | ||||
| { | ||||
|     if (capacity <= mCapacity) | ||||
|         return; | ||||
| 
 | ||||
|     mCapacity = capacity; | ||||
|     char* newData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
| 
 | ||||
|     for (std::size_t i = 0; i < mSize; ++i) | ||||
|         newData[i] = mpData[i]; | ||||
|     newData[mSize] = '\0'; | ||||
| 
 | ||||
|     std::free(mpData); | ||||
|     mpData = newData; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void String::resize(std::size_t size) | ||||
| { | ||||
|     reserve(size + 1); | ||||
|     mSize = size; | ||||
|     mpData[mSize] = '\0'; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| String& String::operator=(const String& right) | ||||
| { | ||||
|     if (this == &right) | ||||
|         return *this; | ||||
| 
 | ||||
|     mSize = right.mSize; | ||||
|     resize(mSize); | ||||
| 
 | ||||
|     for (std::size_t i = 0; i <= mSize; ++i) | ||||
|         mpData[i] = right.mpData[i]; | ||||
| 
 | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| String String::operator+(const String& b) | ||||
| { | ||||
|     String result; | ||||
|     result.resize(mSize + b.mSize); | ||||
| 
 | ||||
|     for (std::size_t i = 0; i < mSize; ++i) | ||||
|         result.mpData[i] = mpData[i]; | ||||
| 
 | ||||
|     for (std::size_t i = 0; i < b.mSize; ++i) | ||||
|         result.mpData[mSize + i] = b.mpData[i]; | ||||
| 
 | ||||
|     result.mpData[result.mSize] = '\0'; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| String& String::operator+=(const String& right) | ||||
| { | ||||
|     *this = *this + right; | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| bool String::operator==(const String& right) const | ||||
| { | ||||
|     if (mSize != right.mSize) | ||||
|         return false; | ||||
| 
 | ||||
|     std::size_t i = 0; | ||||
|     while (i < mSize && mpData[i] == right.mpData[i]) | ||||
|         i++; | ||||
| 
 | ||||
|     return i == mSize; | ||||
| } | ||||
| 
 | ||||
| bool String::operator<(const String& right) const | ||||
| { | ||||
|     std::size_t i = 0; | ||||
|     while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i]) | ||||
|         i++; | ||||
| 
 | ||||
|     return mpData[i] < right.mpData[i]; | ||||
| } | ||||
| 
 | ||||
| bool String::operator<=(const String& right) const | ||||
| { | ||||
|     std::size_t i = 0; | ||||
|     while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i]) | ||||
|         i++; | ||||
| 
 | ||||
|     return mpData[i] <= right.mpData[i]; | ||||
| } | ||||
| 
 | ||||
| bool String::operator!=(const String& right) const | ||||
| { | ||||
|     return !(*this == right); | ||||
| } | ||||
| 
 | ||||
| bool String::operator>(const String& right) const | ||||
| { | ||||
|     return !(*this <= right); | ||||
| } | ||||
| 
 | ||||
| bool String::operator>=(const String& right) const | ||||
| { | ||||
|     return !(*this < right); | ||||
| } | ||||
| 
 | ||||
| char& String::operator[](std::size_t i) | ||||
| { | ||||
|     return mpData[i]; | ||||
| } | ||||
| 
 | ||||
| char& String::at(std::size_t i) | ||||
| { | ||||
|     if (i >= mSize) | ||||
|     { | ||||
|         std::cout << "Error! Index is out of bounds." << std::endl; | ||||
|         std::exit(1); | ||||
|     } | ||||
|     return mpData[i]; | ||||
| } | ||||
| 
 | ||||
| void String::clear() | ||||
| { | ||||
|     std::free(mpData); | ||||
| 
 | ||||
|     mSize = 0; | ||||
|     mCapacity = 1; | ||||
|     mpData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
|     mpData[0] = '\0'; | ||||
| } | ||||
| 
 | ||||
| void String::addCharacter(char c) | ||||
| { | ||||
|     if (mSize + 1 == mCapacity) | ||||
|         reserve(2 * mCapacity); | ||||
| 
 | ||||
|     mpData[mSize] = c; | ||||
|     resize(mSize + 1); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::size_t String::getSize()        const   {return mSize;} | ||||
| std::size_t String::getCapacity()    const   {return mCapacity;} | ||||
| const char* String::cStr()      const   {return mpData;} | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, const String& s)  | ||||
| { | ||||
|     out << s.cStr(); | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| std::istream& operator>>(std::istream& in, String& s)  | ||||
| { | ||||
|     s.clear(); | ||||
|     while (true) | ||||
|     { | ||||
|         char x = in.get(); | ||||
|         if (x == ' ' || x == '\n' || x == '\t') | ||||
|             break; | ||||
|         s.addCharacter(x); | ||||
|     } | ||||
|     return in; | ||||
| } | ||||
|  | @ -0,0 +1,51 @@ | |||
| #pragma once | ||||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| 
 | ||||
| 
 | ||||
| class String  | ||||
| { | ||||
| private: | ||||
| 
 | ||||
|     std::size_t mSize; | ||||
|     std::size_t mCapacity; | ||||
|     char* mpData; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     String(const char* str); | ||||
| 
 | ||||
|     String(); | ||||
|     String(const String& s); | ||||
| 
 | ||||
|     String(std::size_t n, char a); | ||||
|     ~String(); | ||||
| 
 | ||||
|     void reserve(std::size_t capacity); | ||||
|     void resize(std::size_t size); | ||||
| 
 | ||||
|     String& operator=(const String& right); | ||||
|     String operator+(const String& b); | ||||
|     String& operator+=(const String& right); | ||||
| 
 | ||||
|     bool operator==(const String& right) const; | ||||
|     bool operator<(const String& right) const; | ||||
|     bool operator<=(const String& right) const; | ||||
|     bool operator!=(const String& right) const; | ||||
|     bool operator>(const String& right) const; | ||||
|     bool operator>=(const String& right) const; | ||||
| 
 | ||||
|     char& operator[](std::size_t i); | ||||
|     char& at(std::size_t i); | ||||
| 
 | ||||
|     void clear(); | ||||
|     void addCharacter(char c); | ||||
| 
 | ||||
|     std::size_t getSize()        const; | ||||
|     std::size_t getCapacity()    const; | ||||
|     const char* cStr()      const; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, const String& s); | ||||
| std::istream& operator>>(std::istream& in, String& s); | ||||
|  | @ -0,0 +1,32 @@ | |||
| #include <iostream> | ||||
| #include "string.hpp" | ||||
| using std::cout, std::cin, std::endl; | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     mipt::String a = "Mouse"; | ||||
|     mipt::String b; | ||||
|     cin >> b; | ||||
|     mipt::String c = b; | ||||
| 
 | ||||
|     if (a + c == "MouseLion") | ||||
|         cout << "Yes" << endl; | ||||
|     else | ||||
|         cout << "No" << endl; | ||||
| 
 | ||||
| 
 | ||||
|     if (a > "Mice") | ||||
|         cout << "Yes" << endl; | ||||
|     else | ||||
|         cout << "No" << endl; | ||||
| 
 | ||||
| 
 | ||||
|     c[0] = 'P'; | ||||
|     cout << c << endl; | ||||
| 
 | ||||
|     c += a; | ||||
|     cout << c << endl; | ||||
| 
 | ||||
|     c = c + mipt::String(10, 'q'); | ||||
|     cout << c << endl; | ||||
| } | ||||
|  | @ -0,0 +1,207 @@ | |||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| #include "string.hpp" | ||||
| 
 | ||||
| namespace mipt { | ||||
| 
 | ||||
| String::String(const char* str)  | ||||
| { | ||||
|     std::size_t i = 0; | ||||
|     while (str[i] != '\0') | ||||
|         i++; | ||||
|     mSize = i; | ||||
|     mCapacity = i + 1; | ||||
| 
 | ||||
|     mpData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
| 
 | ||||
|     for (std::size_t i = 0; str[i]; i++) | ||||
|         mpData[i] = str[i]; | ||||
|     mpData[mSize] = '\0'; | ||||
| } | ||||
| 
 | ||||
| String::String() : String("") {} | ||||
| String::String(const String& s) : String(s.cStr()) {} | ||||
| 
 | ||||
| String::String(std::size_t n, char a) | ||||
| { | ||||
|     mSize = n; | ||||
|     mCapacity = n + 1; | ||||
|     mpData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
| 
 | ||||
|     for (std::size_t i = 0; i < mSize; ++i) | ||||
|         mpData[i] = a; | ||||
|     mpData[mSize] = '\0'; | ||||
| } | ||||
| 
 | ||||
| String::~String() | ||||
| { | ||||
|     std::free(mpData); | ||||
| } | ||||
| 
 | ||||
| void String::reserve(std::size_t capacity) | ||||
| { | ||||
|     if (capacity <= mCapacity) | ||||
|         return; | ||||
| 
 | ||||
|     mCapacity = capacity; | ||||
|     char* newData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
| 
 | ||||
|     for (std::size_t i = 0; i < mSize; ++i) | ||||
|         newData[i] = mpData[i]; | ||||
|     newData[mSize] = '\0'; | ||||
| 
 | ||||
|     std::free(mpData); | ||||
|     mpData = newData; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void String::resize(std::size_t size) | ||||
| { | ||||
|     reserve(size + 1); | ||||
|     mSize = size; | ||||
|     mpData[mSize] = '\0'; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| String& String::operator=(const String& right) | ||||
| { | ||||
|     if (this == &right) | ||||
|         return *this; | ||||
| 
 | ||||
|     mSize = right.mSize; | ||||
|     resize(mSize); | ||||
| 
 | ||||
|     for (std::size_t i = 0; i <= mSize; ++i) | ||||
|         mpData[i] = right.mpData[i]; | ||||
| 
 | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| String String::operator+(const String& b) | ||||
| { | ||||
|     String result; | ||||
|     result.resize(mSize + b.mSize); | ||||
| 
 | ||||
|     for (std::size_t i = 0; i < mSize; ++i) | ||||
|         result.mpData[i] = mpData[i]; | ||||
| 
 | ||||
|     for (std::size_t i = 0; i < b.mSize; ++i) | ||||
|         result.mpData[mSize + i] = b.mpData[i]; | ||||
| 
 | ||||
|     result.mpData[result.mSize] = '\0'; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| String& String::operator+=(const String& right) | ||||
| { | ||||
|     *this = *this + right; | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| bool String::operator==(const String& right) const | ||||
| { | ||||
|     if (mSize != right.mSize) | ||||
|         return false; | ||||
| 
 | ||||
|     std::size_t i = 0; | ||||
|     while (i < mSize && mpData[i] == right.mpData[i]) | ||||
|         i++; | ||||
| 
 | ||||
|     return i == mSize; | ||||
| } | ||||
| 
 | ||||
| bool String::operator<(const String& right) const | ||||
| { | ||||
|     std::size_t i = 0; | ||||
|     while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i]) | ||||
|         i++; | ||||
| 
 | ||||
|     return mpData[i] < right.mpData[i]; | ||||
| } | ||||
| 
 | ||||
| bool String::operator<=(const String& right) const | ||||
| { | ||||
|     std::size_t i = 0; | ||||
|     while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i]) | ||||
|         i++; | ||||
| 
 | ||||
|     return mpData[i] <= right.mpData[i]; | ||||
| } | ||||
| 
 | ||||
| bool String::operator!=(const String& right) const | ||||
| { | ||||
|     return !(*this == right); | ||||
| } | ||||
| 
 | ||||
| bool String::operator>(const String& right) const | ||||
| { | ||||
|     return !(*this <= right); | ||||
| } | ||||
| 
 | ||||
| bool String::operator>=(const String& right) const | ||||
| { | ||||
|     return !(*this < right); | ||||
| } | ||||
| 
 | ||||
| char& String::operator[](std::size_t i) | ||||
| { | ||||
|     return mpData[i]; | ||||
| } | ||||
| 
 | ||||
| char& String::at(std::size_t i) | ||||
| { | ||||
|     if (i >= mSize) | ||||
|     { | ||||
|         std::cout << "Error! Index is out of bounds." << std::endl; | ||||
|         std::exit(1); | ||||
|     } | ||||
|     return mpData[i]; | ||||
| } | ||||
| 
 | ||||
| void String::clear() | ||||
| { | ||||
|     std::free(mpData); | ||||
| 
 | ||||
|     mSize = 0; | ||||
|     mCapacity = 1; | ||||
|     mpData = (char*)std::malloc(sizeof(char) * mCapacity); | ||||
|     mpData[0] = '\0'; | ||||
| } | ||||
| 
 | ||||
| void String::addCharacter(char c) | ||||
| { | ||||
|     if (mSize + 1 == mCapacity) | ||||
|         reserve(2 * mCapacity); | ||||
| 
 | ||||
|     mpData[mSize] = c; | ||||
|     resize(mSize + 1); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::size_t String::getSize()        const   {return mSize;} | ||||
| std::size_t String::getCapacity()    const   {return mCapacity;} | ||||
| const char* String::cStr()      const   {return mpData;} | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, const String& s)  | ||||
| { | ||||
|     out << s.cStr(); | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| std::istream& operator>>(std::istream& in, String& s)  | ||||
| { | ||||
|     s.clear(); | ||||
|     while (true) | ||||
|     { | ||||
|         char x = in.get(); | ||||
|         if (x == ' ' || x == '\n' || x == '\t') | ||||
|             break; | ||||
|         s.addCharacter(x); | ||||
|     } | ||||
|     return in; | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,54 @@ | |||
| #pragma once | ||||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| 
 | ||||
| namespace mipt { | ||||
| 
 | ||||
| class String  | ||||
| { | ||||
| private: | ||||
| 
 | ||||
|     std::size_t mSize; | ||||
|     std::size_t mCapacity; | ||||
|     char* mpData; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     String(const char* str); | ||||
| 
 | ||||
|     String(); | ||||
|     String(const String& s); | ||||
| 
 | ||||
|     String(std::size_t n, char a); | ||||
|     ~String(); | ||||
| 
 | ||||
|     void reserve(std::size_t capacity); | ||||
|     void resize(std::size_t size); | ||||
| 
 | ||||
|     String& operator=(const String& right); | ||||
|     String operator+(const String& b); | ||||
|     String& operator+=(const String& right); | ||||
| 
 | ||||
|     bool operator==(const String& right) const; | ||||
|     bool operator<(const String& right) const; | ||||
|     bool operator<=(const String& right) const; | ||||
|     bool operator!=(const String& right) const; | ||||
|     bool operator>(const String& right) const; | ||||
|     bool operator>=(const String& right) const; | ||||
| 
 | ||||
|     char& operator[](std::size_t i); | ||||
|     char& at(std::size_t i); | ||||
| 
 | ||||
|     void clear(); | ||||
|     void addCharacter(char c); | ||||
| 
 | ||||
|     std::size_t getSize()        const; | ||||
|     std::size_t getCapacity()    const; | ||||
|     const char* cStr()      const; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, const String& s); | ||||
| std::istream& operator>>(std::istream& in, String& s); | ||||
| 
 | ||||
| } | ||||
		Reference in a new issue