C++ Chanel
617 subscribers
44 photos
6 videos
53 links
Download Telegram
C++ Chanel
#include <iostream> class Artist { public: void Start() { Requesting(); } private: void Requesting() { std::string figure; bool run = 0; // run будет равна false std::cout << "Write what figure you want to draw:…
тут я мог и использовать стейтмент,как и в олимпиадных задачах,там где используются только стандартная библиотека.Но про реальные проекты написано в ссылке сверху
Решение:
class Solution {
public:
int maxLengthBetweenEqualCharacters(string s) {

int result {-1};

for(int i = 0;i<s.size();++i){

for(int j = i+1;j<s.size();++j){

if(s[i] == s[j])
result = max(j-i-1,result);

}
}

return result;
}
};
1
История о том как появились foo и baz

Если кто-то не знает foo bar и baz это очень распространенные метки среди программистов,они очень часто используются в примерах разных документаций или на форумах.Примеры на фото выше.

1.Взято со stack overflow:
Foo и bar произошли от армейского акронима времён Второй мировой, FUBAR — “Fucked Up Beyond All Recognition” (англ. “Разбито в хлам”). Во время кампаний в Северной Африке и Сицилии (1942–1943) возникло целое семейство таких сокращений, которые можно найти в книге Рика Эткинсона Day of Battle: The War in Sicily and Italy, 1943-1944. Например, сокращение JANFU означает “Joint Army Navy Fucked Up” (англ. “Союз армии и флота облажался”), и применялось, в частности, для описания инцидента 11 июля 1943 года, когда британский флот сбил 23 транспортных самолёта США с десантом.


В реальном деве переменная не должна быть бессмысленной!!!!
Например в циклах i,j,k и так далее (от итерации)
Немножечко про set,как найти последний элемент в сете ( самый большой ):

в С++ set это структура данных которая хранит набор уникальных элементов.Это значит, что каждый элемент в сете может присутствовать только один раз.Элементы в сете не имеют определенного порядка. Это означает, что вы не можете получить доступ к элементам сета по индексу, как в массиве или списке.В стандартной библиотеке C++ контейнер std::set обычно реализуется как красно-черное дерево. Красно-черное дерево является одной из наиболее эффективных реализаций сбалансированных деревьев поиска, которые обеспечивают операции вставки, удаления и поиска за логарифмическое время в среднем. Фото красно-черного дерева выше!!!

Set довольно часто использую в задачах как и map который также реализуется через красно-черное дерево.
К примеру: https://codeforces.com/problemset/problem/469/A простенькая задача идея которой взять два массива и соединить их в сет( из двух массивов {2,3,3} и {1,4,66,5} мы получим один сет {1,2,3,4,5,66})
Также нам нужно проверить какой самый большой элемент из двух массивов.Но как же это сделать???Можно завести переменную,но можно сделать еще легче через указатель для доступа к элементам контейнера.Для того чтобы получить последний элемент мы сначала получаем итератор на последний элемент множества a с помощью a.end(), а затем сдвигаем его на один элемент назад с помощью операции декремента --. И, наконец, с помощью операции разыменования * мы получаем значение элемента, на который указывает этот итератор, то есть мы получили последний элемент множества a.
*—a.end()
❤‍🔥1
Решение задачи:

#include <iostream>
#include <set>
using namespace std;
int main()
{
int n;
cin >> n;
int p;
int q;
set<int> res;
cin >> p;
for (int i = 0; i < p; ++i) {
int temp;
cin >> temp;
res.insert(temp);
}
cin >> q;
for (int i = 0; i < q; ++i) {
int temp;
cin >> temp;
res.insert(temp);
}
if (res.size() == n && *--res.end() == n) {
cout << "I become the guy.";
}
else {
cout << "Oh, my keyboard!";
}

return 0;
}
🍓3
Супер интересная задача на знания контейнеров map и кодировочных наборов ( Следующий пост про них )

https://codeforces.com/problemset/problem/1927/B
Решение и объяснение будет в след посте
Решение задачи:
#include <iostream>
#include <set>
#include <map>
#include <vector>
using namespace std;


int main() {
int t{};
cin>>t;
vector<string> res;
for(int g = 0;g<t;++g){
int n;
cin>>n;
string result;
vector<int> v(n,0);
for(int i = 0;i<n;++i){
cin>>v[i];
}
map<char,int> m;

for(int i = 0;i<n;++i){
int w = 97;
for(int j = 0;j<26;++j){
if(m[w] == v[i]){
result+=(char)(w);
++m[w];
break;
}else{
w++;
}
}
}
res.push_back(result);
}
for(string s : res){
cout<<s<<endl;
}

return 0;
}
Как решить эту задачу?

Перед тем как решать ее нужно узнать как использовать map.
Если кто-то не знает - map ассоциативный контейнер основанный на ключах и значениях.Каждый элемент в map представляет собой пару ключ-значение, где ключ уникален внутри контейнера.Если вы обратитесь к любому ключу, он автоматически создан.Например, у нас есть map<char,int>:

std::map<char,int> m;
if ( m['a'] == 0 ){
std::cout<<"zero";
}


Таким образом у нас будет автоматически сохранено значение 0 в ключ 'a'.

Также как и set,использует красно-черное бинарное дерево для хранение элементов,Это обеспечивает быстрый и эффективный поиск элементов по ключу.На удаление и вставку за логарифмическое время , занимает (O(log n)),Логарифмическое время означает, что время выполнения алгоритма растет не пропорционально размеру входных данных, а логарифмически зависит от размера входных данных.
Указатели на функцию???

Да,в С++ такое возможно в качестве переменной или аргумента.
Недавно перечитывал cplusplus.com и увидел что в параметры можно принимать не только обычные типы,а и void что меня удивило.
int square(int x) {
return x * x;
}

int main() {
int (*myPointer)(int) = square;

std::cout << "Квадрат: " << myPointer(5) << std::endl;


}

Если мы напишем вот так то строка int(*myPointer)(int) = square; будет r_value.

Или можно сделать указатель на функцию в параметры:
void foo(int (*function)(int), int value) {
int result = function(value);
std::cout << "Result: " << result << std::endl;
}

int square(int x) {
return x * x;
}

int main() {
int (*myPointer)(int) = square;

foo(myPointer, 3);
}
👍3
Вот еще один пример из самого cplusplus.com :
void increase (void* data, int psize)
{
if ( psize == sizeof(char) )
{ char* pchar; pchar=(char*)data; ++(*pchar); }
else if (psize == sizeof(int) )
{ int* pint; pint=(int*)data; ++(*pint); }
}

int main ()
{
char a = 'x';
int b = 1602;
increase (&a,sizeof(a));
increase (&b,sizeof(b));
cout << a << ", " << b << '\n';
return 0;
}
Что такое умные указатели в С++?

Я думаю,что все знают что такое указатель(raw pointer) или необработанный указатель.Но для обычных указателей нужно особое внимание,так как они с легкостью сломают ваше приложение.Ихнее управление зависит только от вас,если вы динамически выделяете память( new some_type ),то вы должны удалить его в ручную ( delete some_type ) в массивах за это отвечает другой оператор( один из таких: delete[] ).И во время написания кода,вам нужно помнить какой оператор нужно использовать.А если вы случайно ошиблись - может привести к неопределенному поведению / Undefined behavior .

Чтобы избегать проблем с утечкой памяти,придумали умные указатели.Они сами делают деаллокацию,например когда вы выходите из функции (и многое другое).На самом деле,умные указатели это просто класс который проводит все манипуляции под капотом.Насчет деалокации - просто срабатывает деструктор класса который освобождает выделенную память.

Начиная с С++11 появилось три основных типа умных указателей:
std::unique_ptr — умный указатель, владеющий динамически выделенным ресурсом.
std::shared_ptr — это умный указатель, который управляет разделяемым динамически выделенным ресурсом. Он поддерживает совместное владение ресурсом несколькими std::shared_ptr, и внутренний счетчик отслеживает количество указателей, владеющих ресурсом.
std::weak_ptr — подобен std::shared_ptr, но не увеличивает счетчик.
Что автоматически перегружаеться при создании объекта с++?

При создании любого объекта автоматически происходит перегрузка нескольких операций а именно:

-Конструктор
Он перегружаеться для создания и инициализации объекта.Если не определить собственный - то компилятор сделает это за вас.

-Деструктор
Деструктор вызывается при удаления объекта и освобождает ресурсы занятые объектом.Если не определить собственный - то компилятор сделает это за вас.

-Конструктор копирования
Этот конструктор копирует значения членов одного объекта в другой объект того же типа.Если не определить собственный - то компилятор сделает это за вас.

-Оператор присваивания
Если вы не определите собственный оператор присваивания (operator=), компилятор сгенерирует его для вас. Этот оператор копирует один объект в другой, что позволяет выполнить присваивание между объектами.

-Конструктор перемещения
Представляет альтернативу конструктору копирования в тех ситуациях, когда надо сделать копию объекта, но копирование данных нежелательно - вместо копирования данных они просто перемещаются из одной копии объекта в другую.


"Если не определить собственный - то компилятор сделает это за вас."

Давайте посмотрим на код и сами в этом убедимся:
#include <iostream>

class Chiken {
private:
int m_age;
std::string m_name;
public:
Chiken(int age, std::string name) :m_age(age), m_name(name) {
std::cout << "Constructor called" << std::endl;
}
int GetAge() const { return m_age; }
std::string GetName() const { return m_name; }
};

int main() {
Chiken chik1;
std::cout<<chik1.GetName();
}


Такой код не получиться запустить так как не существует конструктора по умолчанию.
Для того чтобы исправить этот код нужно либо сделать автоматические значения либо перегрузить конструктор без параметров.

Код:
#include <iostream>

class Chiken {
private:
int m_age;
std::string m_name;
public:
Chiken(int age = 0, std::string name = "Unnamed") :m_age(age), m_name(name) {
std::cout << "Constructor called" << std::endl;
}
int GetAge() const { return m_age; }
std::string GetName() const { return m_name; }
};

int main() {
Chiken chik;//вызов конструктора
Chiken chik1(12,"Vasya");//вызов конструктора
std::cout<<chik.GetName()<<std::endl;
Chiken chik2 = chik1;//Оператор присваивания
Chiken chik3(chik2); //Копирования конструктора
std::cout << chik3.GetAge();
}// вызов деструктора
Абстрактные классы

Ключевое слово class в С++ используется для объявления пользовательского типа данных.Так же это очень мощный инструмент ООП который позволяет объединять данные и методы в один объект.

Если мы хотим создать иерархию классов животных: собак,лошадей,кошек,свиней.Что нам делать?Тут вступает абстрактный класс...

С microsoft документации по С++:
Абстрактные классы используются в качестве обобщенных концепций, на основе которых можно создавать более конкретные производные классы. Невозможно создать объект абстрактного типа класса. Однако можно использовать указатели и ссылки на абстрактные типы классов.

Вы создаете абстрактный класс, объявляя по крайней мере одну чистую виртуальную функцию-член. Это виртуальная функция, объявленная с помощью синтаксиса чистого описателя (= 0). Классы, производные от абстрактного класса, должны реализовывать чисто виртуальную функцию; в противном случае они также будут абстрактными.


То есть для того чтобы класс считался абстрактным нужна хотя-бы одна чисто виртуальная функция (pure-virtual function) .
В нашем случае мы можем сделать наш Animal клас абстрактным и наследовать наши дочерние классы. Рассмотрим на примере:

#include <iostream>

class Animal {
public:
virtual void Speak() const = 0;
virtual ~Animal() {}
};//наш абстрактный класс

class Dog : public Animal{
public:
virtual void Speak() const override { std::cout << "Dog speak! \n"; }
virtual ~Dog() {}
};

class Cat : public Animal {
public:
virtual void Speak() const override { std::cout << "Cat speak! \n"; }
virtual ~Cat() {}
};
int main() {
//Animal* prt = new Animal(); - ошибка
Animal* ptr = new Dog();
ptr->Speak();
delete ptr;
ptr = new Cat();
ptr->Speak();
delete ptr;
}


Вывод:

1. Объект абстрактного класса не может быть создан,но можно выделять динамическую память на дочерние классы через указатель или ссылку.
2. Классы наследники должны переопределить все pure-virtual функции, иначе они остануться абстрактными.
3. В нашем примере класс Animal предоставляет общие функции но он не сможет ходить,бегать,прыгать так как это КАТЕГОРИЯ ОРГАНИЗМОВ - его можно записывать в абстрактные классы.
Что такое и зачем нужны uint32_t , int64_t , uint8_t и тд?

Когда все начинали изучать С++ работали с разными типами данных ( char , int , std::string , bool ).Но на разных архитектурах и разные компиляторы хотят от int разное количество памяти.
Давайте рассмотрим это подробнее:

Влияние архитектуры на размер int
16-битные архитектуры:
На старых 16-битных системах тип int обычно занимал 2 байта (16 бит).

32-битные архитектуры:
На большинстве современных 32-битных систем тип int занимает 4 байта (32 бита). Это связано с тем, что 32-битные процессоры оптимально работают с данными размером 4 байта.

64-битные архитектуры:
На большинстве современных 64-битных систем тип int также занимает 4 байта (32 бита), несмотря на то, что процессоры способны работать с данными большего размера. Это сделано для обеспечения обратной совместимости и эффективности.

Мы можем сделать вывод что на разных устройствах код будет работать по разному.Но что если мы хотим чтобы наша программа работала одинаково на разных компиляторах и архитектурах?

Кроссплатформенность - способность программного обеспечения работать с несколькими аппаратными платформами или операционными системами.

Для того чтобы решить вопрос кроссплатформенности в С++ добавили Целочисленные типы фиксированной ширины.Они имеют один размер не зависимо от архитектуры.

Основные 8:
int8_t - char ( 1 байт)
int16_t - short ( 2 байта )
int32_t - int ( 4 байта )
int64_t - long long ( 8 байт )
Если добавить символ u в начале то будут unsigned типы ( которые не могут быть меньше нуля но хранят в два раза больше положительных чисел).
Все эти типы будут выделять на этапе компиляции столько битов,сколько написано в названии.
1👍1😱1