#include <iostream>
#include <iomanip>
#include <cassert>
#include <cstdint>
#include <cstddef> // для offsetof
#include <locale>  // для setlocale

using namespace std;

// Преобразование значения от 0 до 15 в шестнадцатеричную цифру
char nibble_to_hex(uint8_t i) {
    assert(0x0 <= i && i <= 0xf);
    const char digits[] = "0123456789abcdef";
    return digits[i];
}

// Извлечение младшего nibble
uint8_t get_lower_nibble(uint8_t byte) {
    return byte & 0x0F;
}

// Извлечение старшего nibble
uint8_t get_upper_nibble(uint8_t byte) {
    return byte >> 4;
}

// Печать байта в шестнадцатеричном виде
void print_in_hex(uint8_t byte) {
    cout << nibble_to_hex(get_upper_nibble(byte))
        << nibble_to_hex(get_lower_nibble(byte));
}

// Преобразование void* в uint8_t*
const uint8_t* as_bytes(const void* data) {
    return reinterpret_cast<const uint8_t*>(data);
}

// Печать блока данных в шестнадцатеричном виде
void print_in_hex(const void* data, size_t size) {
    const uint8_t* bytes = as_bytes(data);
    for (size_t i = 0; i < size; i++) {
        print_in_hex(bytes[i]);
        if ((i + 1) % 16 == 0) {
            cout << '\n';
        }
        else {
            cout << ' ';
        }
    }
}

// Печать байта в двоичном виде
void print_in_binary(uint8_t byte) {
    for (int bit = 7; bit >= 0; --bit) {
        cout << ((byte & (1 << bit)) ? '1' : '0');
    }
}

// Печать блока данных в двоичном виде
void print_in_binary(const void* data, size_t size) {
    const uint8_t* bytes = as_bytes(data);
    for (size_t i = 0; i < size; i++) {
        print_in_binary(bytes[i]);
        if ((i + 1) % 4 == 0) {
            cout << '\n';
        }
        else {
            cout << ' ';
        }
    }
}

// Структура Student с изменениями, соответствующими заданию
struct Student {
    char name[17];          // Имя студента (массив из 17 символов)
    uint16_t admissionYear; // Год поступления (2 байта)
    float averageGrade;     // Средний балл (с плавающей запятой)
    uint8_t gender : 1;     // Пол (0 — женский, 1 — мужской)
    uint32_t coursesCount;  // Количество пройденных курсов
    Student* groupLeader;   // Указатель на старосту (для старосты — нулевой указатель)
};

int main() {
    // Устанавливаем локаль для отображения русских букв
    setlocale(LC_ALL, "Russian");

    // 1. Примерные данные для тестирования
    Student students[3] = {
        {"Алексей Петров", 2023, 4.0f, 1, 5, nullptr},  // Мужчина, 5 курсов
        {"Мария Иванова", 2022, 3.8f, 0, 6, nullptr},   // Женщина, 6 курсов
        {"Дмитрий Смирнов", 2021, 4.5f, 1, 7, nullptr}  // Мужчина, 7 курсов
    };

    // 2. Печать информации о массиве студентов
    cout << "\n1) Адрес и размер массива студентов:" << endl;
    cout << "Адрес массива: " << static_cast<void*>(students) << endl;
    cout << "Размер массива: " << sizeof(students) << " байт" << endl;

    // 3. Печать информации о каждом студенте
    for (int i = 0; i < 3; i++) {
        cout << "\n2) Адрес и размеры элементов массива Student[" << i << "]:" << endl;
        cout << "Адрес: " << static_cast<void*>(&students[i]) << endl;
        cout << "Размер: " << sizeof(students[i]) << " байт" << endl;
    }

    // 4. Печать информации о полях первого студента (например, для "Мария Иванова")
    cout << "\n3) Сведения о полях первого студента (Мария Иванова):" << endl;
    Student& maria = students[1];  // Берем второго студента для примера

    // Печать имени
    cout << "Имя:" << endl;
    cout << "Адрес: " << static_cast<void*>(maria.name) << endl;
    cout << "Смещение: " << offsetof(Student, name) << " байт" << endl;
    cout << "Размер: " << sizeof(maria.name) << " байт" << endl;
    cout << "Шестнадцатеричное представление имени: ";
    for (size_t i = 0; i < sizeof(maria.name); i++) {
        cout << hex << (static_cast<int>(maria.name[i]) & 0xFF) << " ";
    }
    cout << "\nДвоичное представление имени: ";
    for (size_t i = 0; i < sizeof(maria.name); i++) {
        for (int bit = 7; bit >= 0; --bit) {
            cout << ((maria.name[i] & (1 << bit)) ? '1' : '0');
        }
        cout << " ";
    }
    cout << "\n\n";

    // Печать года поступления
    cout << "Год поступления:" << endl;
    cout << "Адрес: " << &maria.admissionYear << endl;
    cout << "Смещение: " << offsetof(Student, admissionYear) << " байт" << endl;
    cout << "Размер: " << sizeof(maria.admissionYear) << " байт" << endl;
    cout << "Шестнадцатеричное представление: " << hex << maria.admissionYear << endl;
    cout << "Двоичное представление: ";
    for (int bit = 15; bit >= 0; --bit) {
        cout << ((maria.admissionYear & (1 << bit)) ? '1' : '0');
    }
    cout << "\n\n";

    // Печать среднего балла
    cout << "Средний балл:" << endl;
    cout << "Адрес: " << &maria.averageGrade << endl;
    cout << "Смещение: " << offsetof(Student, averageGrade) << " байт" << endl;
    cout << "Размер: " << sizeof(maria.averageGrade) << " байт" << endl;
    cout << "Шестнадцатеричное представление: " << hex << *reinterpret_cast<uint32_t*>(&maria.averageGrade) << endl; // Преобразуем float к int для вывода
    cout << "Двоичное представление: ";
    uint32_t averageGradeBits = *reinterpret_cast<uint32_t*>(&maria.averageGrade);
    for (int bit = 31; bit >= 0; --bit) {
        cout << ((averageGradeBits & (1 << bit)) ? '1' : '0');
    }
    cout << "\n\n";

    // Печать пола
    cout << "Пол:" << endl;
    cout << "Значение: " << static_cast<int>(maria.gender) << endl; // Просто печать значения
    cout << "Размер (один бит): 1 бит" << endl;
    cout << "\n\n";

    // Печать количества курсов
    cout << "Количество курсов:" << endl;
    cout << "Адрес: " << &maria.coursesCount << endl;
    cout << "Смещение: " << offsetof(Student, coursesCount) << " байт" << endl;
    cout << "Размер: " << sizeof(maria.coursesCount) << " байт" << endl;
    cout << "Шестнадцатеричное представление: " << hex << maria.coursesCount << endl;
    cout << "Двоичное представление: ";
    for (int bit = 31; bit >= 0; --bit) {
        cout << ((maria.coursesCount & (1 << bit)) ? '1' : '0');
    }
    cout << "\n\n";

    // 5. Печать всех студентов в шестнадцатеричном виде
    cout << "4) Все элементы массива студентов в шестнадцатеричном виде:" << endl;
    for (int i = 0; i < 3; i++) {
        cout << "Student[" << i << "] = ";
        for (size_t j = 0; j < sizeof(students[i]); j++) {
            cout << hex << setw(2) << setfill('0') << (static_cast<int>(reinterpret_cast<uint8_t*>(&students[i])[j]) & 0xFF) << " ";
        }
        cout << endl;
    }

    return 0;
}