#include #include #include #include #include #include // Добавлено для работы с кодировкой // Максимумы для буферов (стековые массивы) constexpr std::size_t kMaxFilenameLen = 260; constexpr std::size_t kMaxQueryLen = 256; // Набор запрещенных символов для имени файла (Windows) constexpr const char* kForbidden = "*\"<>?|"; // Проверка валидности имени файла по правилам задания bool validate_filename(const char* name) { // запретные символы for (const char* p = kForbidden; *p; ++p) { if (std::strchr(name, *p)) { return false; } } // двоеточие const char* colon = std::strchr(name, ':'); if (colon) { if (colon != name + 1) return false; // только второй символ if (!std::isalpha(static_cast(name[0]))) return false; if (colon[1] != '\\') return false; // за двоеточием обратная косая } // расширение .txt (если оно есть) const char* dot = std::strrchr(name, '.'); if (dot) { if (std::strlen(dot) != 4) return false; // ".txt" char ext[5]{}; // Исправлено: strncpy_s вместо strncpy strncpy_s(ext, sizeof(ext), dot, 4); for (char& c : ext) c = static_cast(std::tolower(static_cast(c))); if (std::strcmp(ext, ".txt") != 0) return false; } return true; } // Добавить .txt, если точки нет void ensure_txt_extension(char* name, size_t bufferSize) { if (std::strrchr(name, '.') == nullptr) { // Исправлено: strcat_s вместо strcat strcat_s(name, bufferSize, ".txt"); } } // Подсчитать вхождения подстроки sub в строке text int count_occurrences(const char* text, const char* sub) { int count = 0; const std::size_t len = std::strlen(sub); if (len == 0) return 0; const char* pos = text; while ((pos = std::strstr(pos, sub)) != nullptr) { ++count; pos += len; } return count; } int main() { // Настройка кодировки консоли для русского текста SetConsoleOutputCP(1251); SetConsoleCP(1251); // 4.1: ввод имени файла (стековый буфер) char filename[kMaxFilenameLen]{}; std::cout << "Введите имя файла: "; std::cin.getline(filename, kMaxFilenameLen); // 4.2: проверка корректности if (!validate_filename(filename)) { std::cout << "Некорректное имя файла\n"; return 1; } // 4.3: добавить .txt при отсутствии ensure_txt_extension(filename, sizeof(filename)); if (!validate_filename(filename)) { std::cout << "Имя некорректно после добавления .txt\n"; return 1; } // 4.4: чтение файла полностью в динамический буфер FILE* f = nullptr; // Исправлено: fopen_s вместо fopen if (fopen_s(&f, filename, "rb") != 0 || !f) { std::cout << "Не удалось открыть файл: " << filename << "\n"; return 1; } if (std::fseek(f, 0, SEEK_END) != 0) { std::cout << "Ошибка перемещения в конец файла\n"; std::fclose(f); return 1; } long sz = std::ftell(f); if (sz < 0) { std::cout << "Не удалось определить размер файла\n"; std::fclose(f); return 1; } std::rewind(f); char* buffer = static_cast(std::malloc(static_cast(sz) + 1)); if (!buffer) { std::cout << "Не удалось выделить память\n"; std::fclose(f); return 1; } std::size_t read = std::fread(buffer, 1, static_cast(sz), f); if (read != static_cast(sz)) { std::cout << "Ошибка чтения файла\n"; std::free(buffer); std::fclose(f); return 1; } buffer[sz] = '\0'; std::fclose(f); // 4.5: ввод искомой строки (стековый буфер) char query[kMaxQueryLen]{}; std::cout << "Введите строку для поиска: "; std::cin.getline(query, kMaxQueryLen); // 4.6: подсчёт вхождений const std::size_t qlen = std::strlen(query); if (qlen == 0) { std::cout << "Пустая строка поиска\n"; std::free(buffer); return 1; } int hits = count_occurrences(buffer, query); std::cout << "Число вхождений \"" << query << "\": " << hits << "\n"; // 4.7: освобождение памяти std::free(buffer); return 0; }