Библиотека собеса по C++ | вопросы с собеседований
4.63K subscribers
403 photos
2 videos
183 links
Вопросы с собеседований по C++ и ответы на них.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/9ccf302b

Для обратной связи: @proglibrary_feeedback_bot
加入频道
Как получить размер файла в байтах?

В C++17 была добавлена библиотека filesystem, которая упрощает работу с файловой системой

#include <filesystem>

int main()
{
std::uintmax_t size = std::filesystem::file_size("file.txt");
}


❗️Стоит учитывать, что если файл был открыт не только вами, то размер может быть изменён извне
🔥7
🍔 Отладочные макросы

Отладочные макросы в C++ используются для упрощения процесса отладки и диагностики программного кода

Основные отладочные макросы включают assert, static_assert и пользовательские макросы

🍓 assert

Макрос assert определён в заголовочном файле <cassert> и используется для проверки логических выражений во время выполнения программы. Если выражение вернёт false, assert завершает выполнение программы и выводит сообщение об ошибке
#include <cassert>

void test(int x) {
assert(x > 0 && "x must be positive");
// остальной код функции
}

int main() {
test(5); // проходит проверку
test(-3); // приводит к ошибке во время выполнения
return 0;
}


🍒 static_assert

static_assert введён в C++11 и позволяет проверять условия на этапе компиляции. Это особенно полезно для проверки условий, которые должны выполняться всегда, независимо от состояния программы во время выполнения

#include <type_traits>

template <typename T>
void check() {
static_assert(std::is_integral<T>::value, "T must be an integral type");
}

int main() {
check<int>(); // проходит проверку
check<float>(); // ошибка компиляции: T must be an integral type
return 0;
}


❗️Начиная с C++11 и C23 static_assert является ключевым словом

🫐 Пользовательские отладочные макросы

Вы также можете определять собственные макросы для отладки, которые помогут вам выводить дополнительную информацию или выполнять специфические проверки

#include <iostream>

#define DEBUG

#ifdef DEBUG
#define DEBUG_PRINT(x) std::cout << x << std::endl
#else
#define DEBUG_PRINT(x)
#endif

int main() {
int value = 42;
DEBUG_PRINT("Value: " << value);
return 0;
}
👍5🔥1
🍯 Задача с собеседования

Входные данные:
- Дан массив состоящий из int'ов
- Повторяющихся элементов в списке нет

Задача:
- Нужно преобразовать этот массив в строку, сворачивая соседние по числовому ряду числа в диапазоны

Примеры:
[1,4,5,2,3,9,8,11,0] => "0-5,8-9,11"
[1,4,3,2] => "1-4"
[1,4] => "1,4"

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <sstream>

std::string convertToRanges(std::vector<int>& nums) {
if (nums.empty()) {
return "";
}

// Сортируем вектор
std::sort(nums.begin(), nums.end());

std::vector<std::string> ranges;
int start = nums[0];
int prev = start;

for (size_t i = 1; i < nums.size(); ++i) {
if (nums[i] != prev + 1) {
// Если последовательность прервалась, добавляем диапазон
if (start == prev) {
ranges.push_back(std::to_string(start));
}
else {
ranges.push_back(std::to_string(start) + "-" + std::to_string(prev));
}
start = nums[i];
}
prev = nums[i];
}

// Добавляем последний диапазон
if (start == prev) {
ranges.push_back(std::to_string(start));
}
else {
ranges.push_back(std::to_string(start) + "-" + std::to_string(prev));
}

// Объединяем диапазоны в одну строку
std::ostringstream result;
for (size_t i = 0; i < ranges.size(); ++i) {
if (i > 0) {
result << ",";
}
result << ranges[i];
}

return result.str();
}

int main() {
std::vector<int> nums1 = { 1, 4, 5, 2, 3, 9, 8, 11, 0 };
std::cout << convertToRanges(nums1) << std::endl; // Ожидаемый вывод: "0-5,8-9,11"

std::vector<int> nums2 = { 1, 4, 3, 2 };
std::cout << convertToRanges(nums2) << std::endl; // Ожидаемый вывод: "1-4"

std::vector<int> nums3 = { 1, 4 };
std::cout << convertToRanges(nums3) << std::endl; // Ожидаемый вывод: "1,4"

return 0;
}
👍2
Почему использование std::endl может быть менее эффективным, чем \n в некоторых случаях?

Всё дело в буферизации вывода

- std::endl не только добавляет символ новой строки (\n) в поток, но и явно сбрасывает (flushes) буфер вывода. Это означает, что данные из буфера немедленно отправляются в устройство вывода (например, на экран или в файл).

- \n, напротив, просто добавляет символ новой строки в поток без принудительного сброса буфера. Буферизация остаётся управляемой самой стандартной библиотекой, и данные выводятся только тогда, когда буфер заполняется или программа явно вызывает std::flush.

#include <iostream>
#include <chrono>

int main() {
auto start = std::chrono::high_resolution_clock::now();

for (int i = 0; i < 10000; ++i) {
std::cout << "Hello, World!" << std::endl; // Принудительный сброс после каждой строки
}

auto middle = std::chrono::high_resolution_clock::now();

for (int i = 0; i < 10000; ++i) {
std::cout << "Hello, World!\n"; // Буферизация, меньше операций I/O
}

auto end = std::chrono::high_resolution_clock::now();

std::cout << "Time with std::endl: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(middle - start).count()
<< " ms\n";

std::cout << "Time with \\n: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end - middle).count()
<< " ms\n";

return 0;
}


В результате выполния кода будет заметно, что время вывода с \n будет меньше.
👍4
📚 Загадочная библиотека setjmp.h — неочевидный инструмент для управления потоком выполнения


Библиотека setjmp.h предоставляет два необычных макроса:

setjmp — сохраняет текущее состояние программы (регистры, стек) в буфер jmp_buf

longjmp — «откатывает» выполнение к сохранённому состоянию, как прыжок во времени



#include <stdio.h>
#include <setjmp.h>

jmp_buf jump_buffer;

void risky_function() {
printf("Готовимся к прыжку...\n");
longjmp(jump_buffer, 42); // Прыжок обратно в setjmp!
}

int main() {
int ret = setjmp(jump_buffer);
if (ret == 0) {
printf("Первая инициализация...\n");
risky_function();
} else {
printf("Вернулись с кодом: %d\n", ret); // Выведет 42!
}
return 0;
}


⚠️ Осторожно!

• Не заменяет исключения — нет вызова деструкторов (как в C++)
• Опасность утечек — если между setjmp и longjmp выделялась память, она не освободится
• Портит стек — может сломать логику функций

🛠 Где может пригодиться?

• Обработка критических ошибок (а-ля «аварийный выход»)
• Код для встраиваемых систем, где нужно быстро восстановить состояние
• Нестандартные хаки (но лучше так не делать 😈)

Библиотека C/C++ разработчика
🥱3👍2
Какое утверждение о модулях C++20 является верным?
Anonymous Quiz
57%
Модули компилируются быстрее заголовочных файлов и не подвержены проблемам One Definition Rule
5%
Модули могут экспортировать только классы, но не функции
13%
Модули автоматически решают все проблемы циклических зависимостей
4%
Модули работают только с компилятором GCC