2

Why is this illegal in C? What is wrong with reinitializing p to a different posn? The same effect can be achieved by changing the field values individually so I don't understand why it can't be done in one step with p = {1, 2}.

struct posn {
    int x;
    int y;
};

int main() {
    struct posn p = {3, 4};
    p = {1, 2}; //Causes error
    // must do p.x = 1; p.y = 2;
    return 0;
}
Tan Wang
  • 811
  • 1
  • 6
  • 16
  • Initializer lists can only be used in variable declarations. – Iharob Al Asimi Mar 01 '15 at 18:05
  • "Why" is usually not the right question (if only "because"...) Are you looking for this? http://stackoverflow.com/questions/330793/how-to-initialize-a-struct-in-ansi-c – Jongware Mar 01 '15 at 18:12

3 Answers3

5

That's the way the language is specified.

To stay somewhat consistent with C's general design, in order to allow p = {1, 2}, {1, 2} would have to be an expression. But of what type? It could be int[2], or struct { int a; short s; }, or a lot of other things.

With C99, a compound literal can be used, which explicitly mentions the type (and thereby solves the problem of how to determine the type), a parenthesized type-name followed by an initializer in {} brackets:

p = (struct posn){1, 2};
mafso
  • 5,433
  • 2
  • 19
  • 40
  • Thank you for explaining this; I didn't realize that the braces can represent something other than a posn. – Tan Wang Mar 01 '15 at 18:16
4

You may use a compound literal. For example

#include <stdio.h>

struct posn 
{
    int x;
    int y;
};

int main(void) 
{
    struct posn p = { 3, 4 };
    p = ( struct posn ){ 1, 2 };

    printf( "p.x = %d, p.y = %d\n", p.x, p.y );

    return 0;
}

The program output is

p.x = 1, p.y = 2

This works because structures opposite to arrays have copy assignment operator. However you can enclose an array in structure and use the same trick to reassign arrays.

Here is an example

#include <stdio.h>

struct posn 
{
    int a[2];
};

int main(void) 
{
    struct posn p = { { 3, 4 } };
    p = ( struct posn ){ { 1, 2 } };

    printf( "p.a[0] = %d, p.a[1] = %d\n", p.a[0], p.a[1] );

    return 0;
}

Thus it looks like std::array in C++.:)

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

That is not entirely true, you can't use the initializer list but you certainly can initialize or more precisely change the members of your struct whenever you want, try this

p.x = 1;
p.y = 2;

initializer lists can only be part of a declaration.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • 1
    That's exactly what I'm asking. Why can't I create a new posn with {1, 2} and assign p to it with p = {1, 2}; ? – Tan Wang Mar 01 '15 at 18:08
  • @TanWang it can be done as you can see from `Vlad`'s answer but in my opinion that doesn't bring any benefit and it can cause problems if you are not very careful, so if you are a beginer don't use that. I don't like because of the cast, it can cause problems. – Iharob Al Asimi Mar 01 '15 at 18:11
  • @iharob: Curious: What problems can be caused by compound literals? – mafso Mar 01 '15 at 18:20
  • @mafso if you are not careful enough and you do this `struct posn p; p = (struct posn){1};` accidentaly then it will be hard to find the problem. – Iharob Al Asimi Mar 01 '15 at 18:22
  • @iharob: That doesn't look more dangerous than `struct posn p = {1};`. I usually avoid casts where possible, but a compound literal isn't a cast and I don't see any drawbacks a cast has. (Consider `const char *foo;`, a cast can (perhaps accidently) remove const (`(int *)foo`), a compound literal can't (`(int *){foo}` doesn't compile) etc.) A compound literal triggers exactly the same implicit conversions as assignment or initialization, a cast can trigger almost every conversion. – mafso Mar 01 '15 at 18:27