Присвоение структуре
Синтаксис использования фигурных скобок ({ .... }
) со списком начальных значений для структуры может использоваться только при определении структуры, например:
orangeProduct productOrdered = { "Chiquita", { 13 } };
Вы не можете использовать его в назначении;этот оператор не имеет правильной грамматики:
productOrdered = { "Chiquita", { 13 } };
Существует два способа присвоить значения структуре, вместо инициализации ее при определении. Один - назначить каждому члену индивидуально:
productOrdered.brand = "Chiquita";
productOrdered.theAmount.individual = 13;
Другой - скопировать его из другой структуры:
productOrdered = SomeOtherProduct;
Мы можем использовать вышеупомянутое с другой функцией C, называемой составной литерал . Составной литерал может использоваться в выражении для предоставления объекта без указания имени. Общая форма составного литерала:
(type) { initial values... }
Хотя (type)
выглядит как приведение, это не так. Этот синтаксис определяет объект, и он может использовать тот же синтаксис для начальных значений, который используется в объявлениях. Это означает, что мы можем инициализировать составной литерал и назначить его структуре:
productOrdered = (orangeProduct) { "Chiquita", { 13 } };
Другие примечания о назначении структуры
Все перечисленные ниже действия имеют одинаковый эффект:
productOrdered = (orangeProduct) { "Chiquita", { 13 } };
productOrdered = (orangeProduct) { "Chiquita", 13 };
productOrdered = (orangeProduct) { "Chiquita", { .individual = 13 } };
productOrdered = (orangeProduct) { "Chiquita", .theAmount.individual = 13 };
В первой из них внутренние скобки указывают, что мы предоставляем начальное значение для подобъекта основного объекта - для объединения amount
внутри orangeProduct
. Как показывает вторая строка, это не требуется, поскольку, если фигурные скобки опущены, компилятор примет несгруппированные начальные значения и в любом случае назначит их членам подобъектов. Тем не менее, полезно явно включать фигурные скобки, так как это позволяет избежать ошибок в более сложных агрегатах и помочь донести намерения до читателей.
В третьей и четвертой формах показано, что мы можем инициализировать членов, используя их имена. Эта форма называется назначенными инициализаторами. Они наиболее полезны, когда вы пропускаете элементы в структуре или хотите инициализировать элемент объединения, отличный от первого в списке.
Однако другой ответ предложил это неверное утверждение:
productOrdered = (orangeProduct){"Chiquita", productOrdered.theAmount.individual = 13 }
Это неправильно, потому что productOrdered.theAmount.individual = 13
не просто начальное значение;это выражение присваивания. Назначается от 13 до productOrdered.theAmount.individual
. Проблема в том, что весь оператор также присваивает значения productOrdered
, в том числе productOrdered.theAmount.individual
. Это нарушает правило в C 2018 6.5 2, которое гласит:
Если побочный эффект на скалярном объекте не секвенирован относительно другого побочного эффекта на том же скалярном объекте или вычисления значения с использованиемзначение того же скалярного объекта, поведение не определено…
Два присваивания productOrdered.theAmount.individual
не секвенированы, потому что ни одно из правил стандарта C не говорит, когда присваивания происходят относительно друг друга. (Когда выражение присваивания обновляет значение объекта, которое называется побочным эффектом, и оно не является частью основной операции оценки выражения.)
Другие примечания
main
должно быть объявлено с int main(void)
или int main(int argc, char *argv)
, а не с void main()
. Он также может быть объявлен с определенными формами, разрешенными вашей реализацией C.
Включите #include <stdio.h>
в ваш код для объявления printf
.
Добавьте точку с запятой к этой строке:
printf("You bought %d oranges\n\n", productOrdered.theAmount.individual)