3

I have the following nested struct definition:

typedef struct {
    int count;
    float cash;
    char item[50];//switch between array and pointer for testing initializers
    //char *item;
}Purchase;

typedef struct {
    int accnt;
    char acct_name[50];
    Purchase purch;
} Acct;

Where for the Purchase struct by itself, the following initializer works:

//Uses member names:
/* 1 */Purchase p = {.count = 4, .cash = 12.56, .item = "thing"};
//  Note: this member:                          ^^^^^^^^^^^^^^^

And for the nested struct Acct the following works:

// No member names:
/* 2 */Acct acct = {100123, "Robert Baily", {15, 12.50, "Tires"}};
//                                                      ^^^^^^^

but when I attempt to use the member name, as in the first example:

// Attempts to use member name, but fails the last one:
/* 3 */Acct acct3 = {.accnt = 100123, .acct_name = "Robert Baily", {acct3.purch.count = 15, acct3.purch.cash = 12.50, acct3.purch.item = "Tires"}};
// error occurs here ->                                                                                                                ^

I get this error: 22, 131 error: array type 'char [50]' is not assignable when using member char item[50]; inPurchase`

And I get this error: 22, 14 error: initializer element is not a compile-time constant When using member char *item; in Purchase (Note only one version of item is part of the struct at any one time, the other is commented)

So, in summary, I can initialize a nested struct okay if not using named assignment statements as in statement /* 2 */ above, but when I attempt to use named assignments as shown for char [] types in statement /* 3 */, it fails.

What am I missing for initializing a char [] or char * when it is a member of the inner struct of a nested struct construct?

I am using the CLANG set to C99

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • Why wouldn't that be `... {.purch.count = 15, .purch.cash = 12.50, .purch.item = "Tires"}}`? – David C. Rankin Mar 18 '20 at 19:38
  • @DavidC.Rankin - I did try that. For those attempts I get the error message: `23, 63 error: field designator 'purch' does not refer to any field in type 'Purchase'`. (even though the other two members are using the same name. `purch.count` and `purch.cash` with no problem) – ryyker Mar 18 '20 at 19:40
  • 1
    Yes, let me go look a little closer. I remember this biting me not to terribly long ago, and I recall the result being that for nested struct you must provide initialization for all members (despite the standard allowing wiggle room), but I'll have to go refresh and look it up. Give me a few minutes. – David C. Rankin Mar 18 '20 at 19:52
  • @DavidC.Rankin - In all of my attempts, I _am_ initializing all members. – ryyker Mar 18 '20 at 20:00

2 Answers2

3

You are trying to compile:

Acct acct3 = {.accnt = 100123, .acct_name = "Robert Baily", 
           {acct3.purch.count = 15, acct3.purch.cash = 12.50, acct3.purch.item = "Tires"}};

This initializer is not valid because acct3.purch is not a field name of Purchase. You only use the innermost field names when initializing.

Acct acct3 = {.accnt = 100123, .acct_name = "Robert Baily", 
              .purch = {.count = 15, .cash = 12.50, .item = "Tires"}};
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
dbush
  • 205,898
  • 23
  • 218
  • 273
  • You nailed it! I had tried this on the third member before posting this question but got another error message. I failed to recognize the error was referring to member 2. ( i had left both member two and member 1 still using `.purch.cash` and `.purch.count`. (my compiler was set to show only one error per statement.) – ryyker Mar 18 '20 at 20:13
  • So, question: Is it the nested `{,,,}` in the initialization statements that allow the compiler to resolve all ambiguities? i.e. to recognize which struct and which member to apply the value to, even when the there may be duplicate member names used in two different nested structs? – ryyker Mar 18 '20 at 20:18
  • 1
    @ryyker Since the designated initializer names are restricted to the innermost scope, those names only apply to the specific type they're initializing. The fact that other structs may have members of the same name don't matter. – dbush Mar 18 '20 at 20:20
  • Section 6.7.9 of the standard is a little unclear here. The issue seems to be a quirk of using the *named-initializer*. Without it, e.g. `{10, "account", {2, 4.6, "item"}}` there is no special treatment required. I'm still looking for a definitive reference. (which I think @dbush just added with the comment) – David C. Rankin Mar 18 '20 at 20:20
  • 1
    @DavidC.Rankin When the fields are not named the initialization occurs in the order that the fields were declared. – dbush Mar 18 '20 at 20:21
  • Yes, I was just reading further, it is captured in [C11 Standard - 6.7.9 (p17-19)](http://port70.net/~nsz/c/c11/n1570.html#6.7.9p17) which in 18 reads `"Each designator list begins its description with the current object associated with the closest surrounding brace pair."` which I think is as close as we get to saying the designator must be followed by the equal sign and then the brace-enclosed list. (at least that is what I recall stumbling through last time I ran into this...) – David C. Rankin Mar 18 '20 at 20:28
  • “You only use the innermost field names” is not the whole story. You can use `.purch.item = "Tires"` at the level where `Acct` is being initialized. (But OP had `acct3.purch.item = …`, which is not a designated initializer but an assignment expression.) – Eric Postpischil Mar 18 '20 at 20:53
0

Neither structure Acct nor structure Purchase have data member name acct3. So this initializer list for the variable Acct acct3

{acct3.purch.count = 15, acct3.purch.cash = 12.50, acct3.purch.item = "Tires"}

is invalid.

Taking into account the error message the compiler considers such a part of the initializer list like this

acct3.purch.item = "Tires"

as an assignment of the data member item of the object acct3 and arrays do not have the assignment operator because they are non-modifiable lvalues.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335