When to use arrow and when dot?

Viewed 450

I've read about it and I mostly get it, but this situation confused me a bit. Why don't we use arrow operator -> in scanf? I understand that dot is used for objects and arrow for pointers but here, g is a pointer to structure.

DOCUMENT *take(int *pn){
        DOCUMENT *g;
        printf("How much documents? ");
        scanf("%d", pn);
        g = (DOCUMENT *)calloc(*pn, sizeof(DOCUMENT));
        for (int i = 0; i < *pn; i++)
        {
            printf("Type in author, name of document and number of pages: ");
            scanf("%s %s %d", g[i].author, g[i].name, &g[i].s );
        }
        return g;
    }
4 Answers

The array index operator [] has a dereference built into it.

g[i] is exactly the same as *(g + i). So g[i] refers to a DOCUMENT, not a DOCUMENT * and thus you use the member access operator . instead of the pointer-to-member operator ->.

If the left operand of the . or -> is a pointer, then you use ->. Otherwise if it is an object (plain variable), then you use ..

In this case g[i] is taking a pointer and doing array subscripting on it. The result of that is an object ("lvalue"), not a pointer, hence g[i]..


Also note operator precedence in expressions like &g[i].s. The array subscripting operator [] and the struct member operator . have same operator precedence - they belong to the same group of postfix operators. But that group has left-to-right operator associativity so [] takes precedence over the .. Then after those two follow &, the unary address operator, with lowest operator precedence in the expression. So operator precedence guarantees that the expression is equivalent to &((g[i]).s).

The subscript operator used with a pointer yields the object pointed to by the pointer expression. That is, for example, this expression

g[i].author

(where g[i] is the i-th element of the array of structures) is equivalent to

( g + i )->author

where g + i is a pointer that points to the i-th element of the array of structures.

The subscript operator g[i] is equivalent to the expression *( g + i ).

You may write

g[i].author

or like

( *( g + i ) ).author

or like

( g + i )->author

Thus this call of scanf

scanf("%s %s %d", g[i].author, g[i].name, &g[i].s );

can be rewritten like

scanf("%s %s %d", ( g + i )->author, ( g + i )->name, &( g + i )->s );

When you write g[i], this is actually equal to *(g + i). That is, you dereference the pointer and it becomes an object again, so you can access it with dot (.) instead of arrow (->).

Related