Структуры и их использование c. Доступ к компонентам структуры. Выравнивание полей в памяти
Последнее обновление: 02.10.2018
Наряду с классами структуры представляют еще один способ создания обственных типов данных в C#. Более того многие примитивные типы, например, int, double и т.д., по сути являются структурами.
Например, определим структуру, которая представляет человека:
Struct User { public string name; public int age; public void DisplayInfo() { Console.WriteLine($"Name: {name} Age: {age}"); } }
Как и классы, структуры могут хранить состояние в виде переменных и определять поведение в виде методов. Так, в данном случае определены две переменные - name и age для хранения соответственно имени и возраста человека и метод DisplayInfo для вывода информации о человеке.
Используем эту структуру в программе:
Using System; namespace HelloApp { struct User { public string name; public int age; public void DisplayInfo() { Console.WriteLine($"Name: {name} Age: {age}"); } } class Program { static void Main(string args) { User tom; tom.name = "Tom"; tom.age = 34; tom.DisplayInfo(); Console.ReadKey(); } } }
В данном случае создается объект tom. У него устанавливаются значения глобальных переменных, и затем выводится информация о нем.
Конструкторы структуры
Как и класс, структура может определять констукторы. Но в отличие от класса нам не обязательно вызывать конструктор для создания объекта структуры:
User tom;
Однако если мы таким образом создаем объект структуры, то обязательно надо проинициализировать все поля (глобальные переменные) структуры перед получением их значений или перед вызовом методов структуры. То есть, например, в следующем случае мы получим ошибку, так как обращение к полям и методам происходит до присвоения им начальных значений:
User tom; int x = tom.age; // Ошибка tom.DisplayInfo(); // Ошибка
Также мы можем использовать для создания структуры конструктор по умолчанию, при вызове которого полям структуры будет присвоено значение по умолчанию (например, для числовых типов это число 0):
User tom = new User(); tom.DisplayInfo(); // Name: Age: 0
Также мы можем определить свои конструкторы. Например, изменим структуру User:
Using System; using System.Reflection; namespace HelloApp { struct User { public string name; public int age; public User(string name, int age) { this.name = name; this.age = age; } public void DisplayInfo() { Console.WriteLine($"Name: {name} Age: {age}"); } } class Program { static void Main(string args) { User tom = new User("Tom", 34); tom.DisplayInfo(); User bob = new User(); bob.DisplayInfo(); Console.ReadKey(); } } }
Важно учитывать, что если мы определяем конструктор в структуре, то он должен инициализировать все поля структуры, как в данном случае устанавливаются значения для переменных name и age.
Также, как и для класса, можно использовать инициализатор для создания структуры:
User person = new User { name = "Sam", age = 31 };
Но в отличие от класса нельзя инициализировать поля структуры напрямую при их объявлении, например, следующим образом:
Struct User { public string name = "Sam"; // ! Ошибка public int age = 23; // ! Ошибка public void DisplayInfo() { Console.WriteLine($"Name: {name} Age: {age}"); } }
Перед тем как приступить к изучению классов в C++, мы рассмотрим тип данных подобный классу — структуры. Структуры полезны, когда нам надо объединить несколько переменных с разными типами под одним именем. Это делает программу более компактной и более гибкой для внесения изменений. Также структуры незаменимы, когда необходимо сгруппировать некоторые данные, например, запись из базы данных или контакт из книги адресов. В последнем случае структура будет содержать такие данные контакта как имя, адрес, телефон и т.п.
Синтаксис
В процессе написания программы может потребоваться сгруппировать разные данные. Например, вы захотите хранить координаты некоторых объектов и их имена. Вы можете сделать это с помощью :
Int x_coor; int y_coor; string names;
Но так как каждый элемент одного массива связан с другим, то при изменении одного, придется менять остальные тоже. И чем больше данных вам надо объединить, тем сложнее будем такая программа. Поэтому для объединения разных данных используются структуры .
Формат объявления структуры выглядит так:
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
Так же как и с простыми типами (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
А теперь только представьте — вы сами можете создавать, своего рода, типы данных, которые вам необходимы и с которыми вам будет удобно работать! И это несложно!
Структура — это, некое объединение различных переменных (даже с разными типами данных), которому можно присвоить имя. Например можно объединить данные об объекте Дом: город (в котором дом находится), улица, количество квартир, интернет(проведен или нет) и т.д. в одной структуре. В общем, можно собрать в одну совокупность данные обо всем, что угодно, точнее обо всем, что необходимо конкретному программисту. Всем сразу стало понятно:)
Если вы только приступаете к знакомству со структурами в С++, сначала, вам необходимо ознакомиться с синтаксисом структур в языке С++ . Рассмотрим простой пример, который поможет познакомиться со структурами и покажет, как с ними работать. В этой программе мы создадим структуру, создадим объект структуры, заполним значениями элементы структуры (данные об объекте) и выведем эти значения на экран. Ну что же, приступим!
#include
В строках 4 — 10 мы создаем структуру. Чтобы ее объявить используем зарезервированное слово struct и даем ей любое, желательно логичное, имя. В нашем случае — building . С правилами именования переменных, вы можете ознакомиться в этой статье . Далее открываем фигурную скобку { , перечисляем 4 элемента структуры через точку с запятой; , закрываем фигурную скобку } и в завершении ставим точку с запятой; . Это будет нашим шаблоном (формой) структуры.
В строке 16 объявляем объект структуры. Как и для обычных переменных, необходимо объявить тип данных. В этом качестве выступит имя нашей созданной структуры — building .
Как же заполнить данными (инициализировать) элементы структуры? Синтаксис таков: Имя объекта далее оператор точка. и имя элемента структуры. Например: apartment1.owner . Таким образом, в строках 18-21 присваиваем данные элементам структуры.
И так, данные мы внесли. Следующий вопрос: «Как к ним обратиться, как работать и использовать их в программе?» Ответ — «Очень просто — так же, как и при инициализации, используя точку. и имя элемента структуры». В строках 23 — 26 выводим заполненные элементы структуры на экран.
И вот что мы увидим в результате, когда скомпилируем нашу программу:
Владелец квартиры: Денис Квартира находится в городе: Симферополь Количество комнат: 5 Стоимость: 150000 $
Что ещё важно знать:
- Объект структуры можно объявить до функции main() . Это выглядело бы так:
- Инициализировать структуру можно и таким способом:
но так делают крайне редко;
- Структуру можно вкладывать в другие структуры (это мы рассмотрим в следующем примере).
Дополним предыдущий пример, чтобы увидеть дополнительные возможности работы со структурами.
Пример:
#include
Коментарии по коду программы:
Строка 17 — создание объекта built типа date в определении структуры building . Строки 42 — 43 : создаем указатель на структуру struct building *pApartment; и далее присваиваем ему адрес уже созданного и заполненного данными объекта pApartment = &apartment1; . Обращаясь к элементам структуры через указатель мы используем оператор -> (тире и знак >) . Это видно в строках 47 — 51.
В строке 62 показано, как можно инициализировать структуру. А именно, можно создать новый объект структуры и присвоить ему одним целым, уже созданный и заполненный данными, объект. В функцию show() передаем объект структуры, как параметр — строка 64. Результат:
Владелец квартиры: Денис
Квартира находится в городе: Симферополь
Количество комнат: 5
Стоимость: 150000 $
Дата постройки: январь 2013
Владелец квартиры: Игорь
Квартира находится в городе: Киев
Количество комнат: 4
Стоимость: 300000 $
Дата постройки: январь 2012
Для продолжения нажмите любую клавишу. . .
Разобрав этот пример, мы увидели на практике следующее:
- структуру можно вкладывать в другую структуру;
- увидели, как создаётся указатель на структуру;
- как нужно обращаться к элементу структуры через указатель. А именно, используя оператор -> ; В примере это было так: apartment0->owner , но можно и так (*apartment0).owner . Круглые скобки, во втором случае, обязательны.
- данные одной структуры можно присвоить другой структуре;
- можно структуру передать в функцию, как параметр (кстати, элементы структуры так же можно передавать в функцию, как параметры).
В дополнение ко всему, следует отметить, что функции могут так же возвращать структуры в результате своей работы. Например:
Building Set() { building object; // формирование объекта //... код функции return object; }
Вот так, вкратце, мы познакомились со структурами в языке С++, попрактиковались на примерах и узнали основы. Это только начало!