0

In the codebase I'm working on, I have two structures defined like so:

typedef struct s1
{
   int   somedata;
   union su
   {
      char      *cptr;
      struct s1 *array;
   }; //line 123
} S1;

typedef struct s2
{
    S1   data;
} S2;

Elsewhere, these structures and members are accessed in a way that confuses me:

S2   *s2_ptr;
s2_ptr->data.array[1].charptr

So I have questions:

Why is it array[1].charptr and not array[1]->charptr since array is a pointer?

When compiled, I get the warning "declaration does not declare anything" on "line 123" in struct s1 above. I've read other questions about this and it seems I need to make the union declaration something like:
union su { ... } SU;
which then causes compiler errors for obvious reasons. Of course then correcting the calls to s2_ptr->data.SU.array[1].charptr fixes the errors. I'm wondering if that Would in any way alter what's happening in how data is accessed? Would anything change?

Thanks for any help.

*Thanks much for all the answers. Cleared me right up.

timrau
  • 22,578
  • 4
  • 51
  • 64
Mike Dannyboy
  • 462
  • 1
  • 4
  • 13

3 Answers3

3

Why is it array[1].charptr and not array[1]->charptr since array is a pointer?

array[1] is not a pointer.

If the code was array->charptr then you'd be right; but it isn't. array[1] is a struct s1 . (This is nothing to do with unions)


The other part of your question: When you have the code like this:

union foo
{
    int x;  
    // etc
};

then this defines a type called union foo, but does not declare any instances of that type. That doesn't change if you are inside a struct definition.

To declare a variable you have to either write:

union foo SU;

or you can do those two things at once by putting the variable name just before the ; at the end of the type definition.

There is a thing called anonymous unions which is in C11 and offered as an extension by some compilers prior to that. To activate anonymous unions you have to take out the union tag though, so the code opens with union { .

M.M
  • 138,810
  • 21
  • 208
  • 365
1

The compiler is complaining because you're not declaring the union member, you're only defining the union.

Your structure and union are depending on each other. The best way to solve this is to prototype them first:

union  myUnion;
struct myFistStruct;
struct mySecondStruct;

Then you can define them properly:

union myUnion
{
    char *pC;
    struct myFistStruct *pS1;
};

struct myFistStruct
{
    int D;
    union myUnion U;
};

struct mySecondStruct
{
    struct myFistStruct S1;
};

Concerning the . and the -> operators. One single rule and you'll never get confused; Lets consider this expression:

(Left Operand) (Operator) (Right Operand)

If the left operand is the structure or the union itself then the operator is (.) and if the left operand is a pointer to the struct or the union then the operator is (->).

So the valid access expressions are the following:

struct mySecondStruct *pS2 = (struct mySecondStruct*)malloc(sizeof(struct mySecondStruct));

// pS2->S1
// pS2->S1.D
// pS2->S1.U
// pS2->S1.U.pC
// pS2->S1.U.pS1
rullof
  • 7,124
  • 6
  • 27
  • 36
1

The union question has been dealt with, but (so far) I don't see a very good explanation of your pointer / array notation question:

Why is it array[1].charptr and not array[1]->charptr since array is a pointer?

array is indeed a pointer, and presumably (but not in the code you've posted) it is initialised to point to a block of memory big enough for, at least, 2 s1 objects. When the code refers to s2_ptr->data.SU.array (with the union field name added in of course) then you are referring to a pointer to this block of memory, which can be regarded as being an array of s1 objects. So s2_ptr->data.SU.array[1] refers to the 2nd object in that array. Since you are referring to a specific object you use dot notation to access its fields - s2_ptr->data.SU.array[1].charptr.

If you wanted to access the first object in that array you could use s2_ptr->data.SU.array->charptr or s2_ptr->data.SU.array[0].charptr.

C gives several ways to dereference a pointer, i.e. to access a specific object via a pointer: *p, p->, p[i] are all very closely related dereferencing operations.

AAT
  • 3,286
  • 1
  • 22
  • 26