Структуры в C++

12-10-27 C/C++ CPP 5

Перед тем как приступить к изучению классов в C++, мы рассмотрим тип данных подобный классу — структуры. Структуры полезны, когда нам надо объединить несколько переменных с разными типами под одним именем. Это делает программу более компактной и более гибкой для внесения изменений. Также структуры незаменимы, когда необходимо сгруппировать некоторые данные, например, запись из базы данных или контакт из книги адресов. В последнем случае структура будет содержать такие данные контакта как имя, адрес, телефон и т.п.

Синтаксис

В процессе написания программы может потребоваться сгруппировать разные данные. Например, вы захотите хранить координаты некоторых объектов и их имена. Вы можете сделать это с помощью массивов:

int x_coor[10];
int y_coor[10];
string names[10];

Но так как каждый элемент одного массива связан с другим, то при изменении одного, придется менять остальные тоже. И чем больше данных вам надо объединить, тем сложнее будем такая программа. Поэтому для объединения разных данных используются структуры.

Формат объявления структуры выглядит так:

struct Car
{ 
    int x_coor; 
    int y_coor; 
    string name;
};

Объявляя структуру, мы вводим в программу наш собственный тип данных, которым можем пользоваться, так же как и стандартными типами, т.е. объявление переменной нашего типа будет таким:

structName variableName;

structName — имя структуры, variableName — имя переменной.

x_coor, y_coor и name — поля нашей структуры. При объявлении структуры мы создаем составной тип данных, с помощью которого можно создавать переменные, которые сочетают в себе несколько значений (например, координаты и имя). Внутри структуры каждому полю мы даем имя, чтобы потом обращаться к этому значению по его имени.

Для доступа к полям структуры используется точка:

// объявляем переменную
Car myCar;

// и используем её
myCar.x_coor = 40;
myCar.y_coor = 40;
myCar.name = "Porche";

Как видите, вы можете хранить в структуре столько полей, сколько вам угодно и они могут иметь разные типы.

Рассмотрим пример, демонстрирующий сочетание массивов и структур.

#include <iostream>
using namespace std;

struct PlayerInfo {
    int skill_level;
    string name;
};
using namespace std;

int main() {
    // как и с обычными типами, вы можете объявить массив структур
    PlayerInfo players[5];
    for (int i = 0; i < 5; i++) {
        cout << "Please enter the name for player : " << i << '\n'; 
        // сперва получим доступ к элементу массива, используя
        // обычный синтаксис для массивов, затем обратимся к полю структуры
        // с помощью точки
        cin >> players[ i ].name;
        cout << "Please enter the skill level for " << players[ i ].name << '\n';
        cin >> players[ i ].skill_level;
    }
    for (int i = 0; i < 5; ++i) {
        cout << players[ i ].name << " is at skill level " << players[i].skill_level << '\n';
    }
}

Так же как и с простыми типами (int, например), вы можете создавать массивы структур. А с каждым элементом этого массива работать так же как и с отдельной переменной. Для доступа к полю name первого элемента массива структур, просто напишите:

players[ 0 ].name

Структуры и функции

Очень часто требуется писать функции, которые принимают структуры в качестве аргумента или возвращают структуру. Например, если вам надо написать небольшую космическую аркаду, вам может понадобится функция для инициализации нового противника:

struct EnemySpaceShip 
{ 
    int x_coordinate;
    int y_coordinate;
    int weapon_power;
}; 
EnemySpaceShip getNewEnemy();

Функция getNewEnemy должна возвращать структуру с инициализированными полями:

EnemySpaceShip getNewEnemy ()
{ 
    EnemySpaceShip ship;
    ship.x_coordinate = 0;
    ship.y_coordinate = 0;
    ship.weapon_power = 20;
    return ship;
}

На самом деле эта функция вернет копию созданной локальной переменной ship. Это значит, что каждое поле структуры будет скопировано в новую переменную. В нашем случае копирование малого количества полей не заметно, но когда вы работаете с большими объемами данных нужно избегать лишних действий, подробнее об этом поговорим в статье про указатели.

Таким образом, для получения новой переменной будем использовать следующий код:

EnemySpaceShip ship = getNewEnemy();

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

Передавать структуры в функцию можно так:

EnemySpaceShip upgradeWeapons (EnemySpaceShip ship)
{ 
    ship.weapon_power += 10;
    return ship;
}

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

Использование функции:

ship = upgradeWeapons(ship);

Когда вызывается функция, переменная ship копируется и изменяется в функции, а когда переменная возвращается, она снова копируется и перезаписывает поля оргинальной переменной.

И наконец, программа для создания и улучшения одного корабля:

struct EnemySpaceShip {
    int x_coordinate;
    int y_coordinate;
    int weapon_power;
};

EnemySpaceShip getNewEnemy() {
    EnemySpaceShip ship;
    ship.x_coordinate = 0;
    ship.y_coordinate = 0;
    ship.weapon_power = 20;
    return ship;
}

EnemySpaceShip upgradeWeapons(EnemySpaceShip ship) {
    ship.weapon_power += 10;
    return ship;
}

int main() {
    EnemySpaceShip enemy = getNewEnemy();
    enemy = upgradeWeapons(enemy);
}

Указатели

Если вы работаете с указателем на структуру, то для доступа к переменным надо использовать оператор «->» вместо точки. Все свойства указателей не изменяются. Пример:

#include <iostream>

using namespace std;

struct xampl {
    int x;
};

int main()
{
    xampl structure;
    xampl *ptr;

    structure.x = 12;
    ptr = &structure;
    cout<< ptr->x;
    cin.get();
}

На этом всё!

Хочешь получать статьи на почту?

Подпишись на обновления!
* Ваш email не будет разглашен/продан. Вы сможете отписаться в любое время.

5 Комментариев

  1. Евгений:

    Очень понятно все, спасибо!

  2. Lkortyik:

    С нетерпением жду следующего урока. Все очень понятно изложено. Спасибо!

  3. Stml:

    Зачем в главной функции нужно employee и structure
    Почему не database.age к примеру
    Заранее извините за тупой вопрос

    1. Dmitriy Vovk:

      database var; //обьявление переменной var типа database (нашего личного типа, который должен быть специально создан , это и есть структура)
      int var2; // обьявление переменной var2 обычного типа , без участия структур

      Поскольку тип database «обьединяет» несколько типов , то к ним нужно «обращяться через точку»:
      employee.age = 22; // Обьект employee нужно обьявить. А в этой строке «дочерний» элемент age (который присутсвует во всех обьектах типа database) получает определенное значение… В общем надеюсь я понял правильно)

  4. Дмитрий:

    Как добавлять новые элементы структуры в коде?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *