- Ввод и вывод содержимого структуры
- Структуры
- Введение
- Объявление структуры
- Начальная инициализация структур
- Определение нового типа
- Указатели на структуру
- Устройство структуры в памяти
- Приведение типов
- Вложенные структуры
- Указатели на поля структуры и на вложенные структуры
- Примеры
- Как вывести содержимое C-структуры?
- ОП, Си — язык со строгой типизацией
- Re: ОП, Си — язык со строгой типизацией
Ввод и вывод содержимого структуры
Вывод значений полей структуры осуществляется аналогично переменным с учетом их типа:
printf(«Имя: %s\n», manager.name);
printf(«Возраст: %d\n», manager.age);
printf(«Зарплата: %g\n», manager.salary);
При вводе необходимо ставить амперсанд:
Оператор точка имеет более высокий приоритет, поэтому ставить скобки, т.е. писать &(manager.age) не нужно. К строке manager.name применимы функции gets() и puts():
Можно также обратиться к отдельным буквам этой строки:
printf(«Имя начинается с буквы %c\n»,
Вложенные структуры
Пусть для каждого сотрудника требуется хранить его адрес, который состоит из нескольких полей: улица (street), номер дома (house) и номер квартиры (flat). В таком случае адрес разумно также представить в виде структуры
и одним из полей структуры Worker сделать структуру Address
Обращение к полям вложенной структуры Address происходит через поля структуры Worker; например, задать адрес сотрудника и вывести его на экран можно так:
printf(«Улица: %s\n», manager.address.street);
printf(«Дом: %d\n», manager.addrress.house);
Массив структур
Как мы отмечали в самом начале, важной причиной введения структур является желание работать со списком записей. Такой список представляется в виде массива структур. Аналогично обычному массиву, где элементами являются числа или символы, в массиве структур элементами являются структуры. Рассмотрим, как объявляется массив структур, в котором будет храниться информация о сотрудниках.
Значения полям элементов массива структур можно задать при его объявлении, перечислив поля в том порядке, который указан при объявлении структуры:
Источник
Структуры
Введение
Мир вокруг можно моделировать различными способами. Самым естественным из них является представление о нём, как о наборе объектов. У каждого объекта есть свои свойства. Например, для человека это возраст, пол, рост, вес и т.д. Для велосипеда – тип, размер колёс, вес, материал, изготовитель и пр. Для товара в магазине – идентификационный номер, название, группа, вес, цена, скидка и т.д.
У классов объектов набор этих свойств одинаковый: все собаки могут быть описаны, с той или иной точностью, одинаковым набором свойств, но значения этих свойств будут разные.
Все самолёты обладают набором общих свойств в пределах одного класса. Если же нам надо более точное описание, то можно выделить подклассы: самолёт амфибии, боевые истребители, пассажирские лайнеры – и в пределах уже этих классов описывать объекты. Например, нам необходимо хранить информацию о сотрудниках компании. Каждый сотрудник, в общем, обладает большим количеством разных свойств. Мы выберем только те, которые нас интересуют для решения прикладной задачи: пол, имя, фамилия, возраст, идентификационный номер. Для работы с таким объектом нам необходима конструкция, которая бы могла агрегировать различные типы данных под одним именем. Для этих целей в си используются структуры.
Объявление структуры
Синтаксис объявления структуры
Полями структуры могут быть любые объявленные типы, кроме самой структуры этого же типа, но можно хранить указатель на структуру этого типа:
В том случае, если несколько полей имеют один тип, то их можно перечислить через запятую:
После того, как мы объявили структуру, можно создавать переменную такого типа с использованием служебного слова struct. Доступ до полей структуры осуществляется с помощью операции точка:
Структура, объявленная в глобальном контексте, видна всем. Структура также может быть объявлена внутри функции:
Можно упростить пример: синтаксис языка позволяет создавать экземпляры структуры сразу же после определения:
Структура также может быть анонимной. Тогда мы не сможем использовать имя структуры в дальнейшем.
В этом примере мы создали переменную A. Она является структурой с двумя полями.
Начальная инициализация структур
Структуру можно инициализировать во время создания как массив. Поля в этом случае будут присваиваться по порядку.
Замечание: таким образом можно только иницализировать структуру. Присваивать значение всей структуре таким образом нельзя.
Современный стандарт си позволяет инициализировать поля структуры по имени. Для этого используется следующий синтакис:
Определение нового типа
Когда мы определяем новую структуру с помощью служебного слова struct, в пространстве имён структур (оно не имеет ничего общего с пространствами имён С++) создаётся новый идентификатор. Для доступа к нему необходимо использовать служебное слово struct. Можно определить новый тип с помощью служебного слова typedef. Тогда будет создан псевдоним для нашей структуры, видимый в глобальном контексте.
Теперь при работе с типом Point нет необходимости каждый раз писать слово struct. Два объявления можно объединить в одно
Замечание. Если мы создаём новый тип-структуру, полем которого является указатель на этот же тип, то его необходимо объявлять явно с использованием служебного слова struct
Указатели на структуру
Указатель на структуру создаётся как обычно. Отличие заключается в том, что можно обращаться к полям структуры через указатель с помощью операции «стрелка» (минус + больше). Пример – пользователь вводит число – размер массива пользователей. Поле этого вводит для каждого из них логин и пароль. Третье поле — идентификатор – задаётся автоматически. После этого все пользователи выводятся на экран.
Обратите внимание на удаление массива структур: при удалении экземпляра структуры он не удаляет своих полей самостоятельно, поэтому необходимо сначала удалять поля, после этого удалять сам массив.
При вызове функции jsonUser мы передаём указатель на экземпляр структуры, поэтому внутри функции доступ до полей осуществляется с помощью оператора стрелка.
Устройство структуры в памяти
Поля структуры расположены в памяти друг за другом. Тип поля определяет сдвиг относительно предыдущего поля. Имя поля — это сдвиг относительно адреса экземпляра. На самом деле размер структуры не всегда равен сумме размеров её полей: это связано с тем, что компилятор оптимизирует расположение структуры в памяти и может поля небольшого размера подгонять до чётных адресов.
Первая структура должна иметь размер 6 байт, вторая 8 байт, третья 7 байт, однако на 32-разрядной машине компилятор VC сделает их все три равными 8 байт. Стандарт гарантирует, что поля расположены друг за другом, но не гарантирует, что непрерывно.
Есть возможность изменить упаковку структур в памяти. Можно явно указать компилятору каким образом производить упаковку полей структуры, объединений или полей класса. Каким образом это делать, зависит от компилятора. Один из самых распространённых способов прагма pack()
У неё есть несколько разновидностей, рассмотрим только одну. pragma pack(n) указывает значение в байтах, используемое для упаковки. Если параметр компилятора не заданы для модуля значения по умолчанию n 8. Допустимыми значениями являются 1, 2, 4, 8 и 16. Выравнивание поля происходит по адресу, кратному n или сумме нескольких полей объекта, в зависимости от того, какая из этих величин меньше.
Использование #pragma pack не приветствуется: логика работы программы не должна зависить от внутреннего представления структуры (если, конечно, вы не занимаетесь системным программированием или ломаете чужие программы и сети).
Приведение типов
Стандартом поведение при приведении одной структуры к другой не определено. Это значит, что даже если структуры имеют одинаковые поля, то нельзя явно кастовать одну структуру до другой.
Этот пример работает, но это хак, которого необходимо избегать. Правильно писать так
Привести массив к структуре (или любому другому типу) по стандарту также невозможно (хотя в различных компиляторах есть для этого инструменты).
Но в си возможно всё.
Но запомните, что в данном случае поведение не определено.
Вложенные структуры
Структура сама может являться полем структуры. Пример: структура Model – модель автомобиля, имеет название, номер, год выпуска и поле Make, которое в свою очередь хранит номер марки и её название.
Вложенные структуры инициализируются как многомерные массивы. В предыдущем примере можно произвести начальную инициализацию следующим образом:
P.S. подобным образом инициализировать строки не стоит, здесь так сделано только для того, чтобы упростить код.
Указатели на поля структуры и на вложенные структуры
Указатели на поля структуры определяются также, как и обычные указатели. Указатели на вложенные структуры возможны только тогда, когда структура определена. Немного переделаем предыдущий пример: «деанонимизируем» вложенную безымянную структуру и возьмём указатели на поля структуры Model:
Как уже говорилось ранее, в си, даже если у двух структур совпадают поля, но структуры имеют разные имена, то их нельзя приводить к одному типу. Поэтому приходится избавляться от анонимных вложенных структур, если на них нужно взять указатель. Можно попытаться взять указатель типа char* на поле структуры, но нет гарантии, что поля будут расположены непрерывно.
Примеры
1. Стек, реализованный с помощью структуры «Узел», которая хранит значение (в нашем примере типа int) и указатель на следующий узел. Это неэффективная реализация, которая требует удаления и выделения памяти под узел при каждом вызове операции push и pop.
2. Реализуем структуру — массив, и некоторые операции для работы с массивами. Тип массива зададим макроподстановкой.
3. Структура Линия, состоит из двух структур точек. Для краткости реализуем только пару операций
Обратите внимание на операции создания и копирования линии. Обязательно нужно копировать содержимое, иначе при изменении или удалении объектов, которые мы получили в качестве аргументов, наша линия также изменится. Если структура содержит другие структуры в качестве полей, то необходимо проводить копирование содержимого всех полей. Глубокое копирование позволяет избежать неявных зависимостей.
4. Структура комплексное число и функции для работы с ней.
Источник
Как вывести содержимое C-структуры?
После нескольких лет джаваскрипта осваиваю сишечку. Не хватает аналога console.dir(object), который выводит на экран содержимое объекта в виде:
Возможно ли такое в си для структур?
Возможно ли такое в си для структур?
Нет. В C нет рефлексии.
Только если через gdb
Значит-таки придется осваивать gdb)
ОП, Си — язык со строгой типизацией
Если у тебя есть структура, то ты наверняка знаешь её тип, вот и выводи её содержимое printf’ом
Если структуру задавал не ТС, можно сделать какую-нибудь фигню вроде
В сишечке? Ну толсто же.
В Си слабая типизация.
Re: ОП, Си — язык со строгой типизацией
А я всегда думал, что С — язык со слабой типизацией.
Может имелась ввиду статическая типизация?
а чего без плюсиков? там можно для структур определить оператор ( 25.09.14 10:09:22 )
там можно для структур определить оператор ★★★★ ( 25.09.14 10:36:30 )
а есть нормальные парсеры для стандартного Си?
эту хреноту можно было бы генерить совершенно автоматически
Что ты подразумеваешь под «нормальными парсерами»?
эту хреноту можно было бы генерить совершенно автоматически
Т.к. это никому нахрен не нужно, то «стандартных» библиотек для этих извращений наверняка нет!
так для плюсиков-то есть решение
откуда-то с просторов интернета, не мое
Сначала, для чистоты кода, будем юзать типизированные выражения. Т.е. вместо int x будем писать (int) x. Вот нужный макрос:
Предполагается что мы будем юзать макрос REFLECTABLE, используемый вот так:
Используя Boost.PP будем проходить по аргументам и генерировать данные:
Чтобы получить доступ к полям, которые приватные, этим кодом добавляется во френды вот такой класс:
Теперь пройдемся по полям, и отдадим эти данные в visitor:
ну и наконец можно использовать.
И наконец, чтобы распечатать поля как хочется ТСу, можно написать такую штуку:
name=
sin_a
credo=«ватник»
action=«язабан»
ура, мы надругались на C++, теперь в нём всё работает!
теперь нужно всё это стереть и перейти на нормальный язык, т.е. на Java или C#
Какое говно. Сколько раз тебе уже предлагали убить себя?
Если запилишь свою рефлексию (через DWARF или что там на венде) — да.
Что ты подразумеваешь под «нормальными парсерами»?
ну например генератор парсеров AntLR автор в оригинале написал как раз для парсанья Си-кода. Он сдавал заказчику огромный кусок работы, написанный на Си. А заказчик сказал, что в комментариях нужно к вообще всему коду, над каждой функцией надписать, какие переменные какого типа в этом коде используются и сколько раз. Автор был достаточно ленив, чтобы ручками всё это выщитывать, поэтому он написал парсер, который раскладывал Си-код в AST, добывал из него нужную информацию и сваливал ее в комментарии.
Хотелось бы что-то такое, только реально использующееся в продакшене, гарантированно хорошо работающее =)
Всё делается ещё проще простым препроцессором
Источник