#include <assert.h>
int main() {

/*
The last section established the difference between these four types:
*/

    float    a  [10] ;          // array
    float (*pa )[10] = & a    ; // pointer to array
    float    a0      =   a[0] ; // element
    float  *pa0      = &(a[0]); // pointer to element

/*
But the expression used for obtaining the pointer to the first element is pedantic.
The root of all C programmer experience with arrays is the shortcut
*/
    float  *pa0x     =   a    ; // (ok)
/*
which reproduces @pa0@, in type and value:
*/
    assert( pa0 == pa0x );
/*
The validity of this initialization is unsettling, in the context of the facts established in the last section.
Notably, it initializes name @pa0x@ from expression @a@, when they are not of the same type:
*/
    assert( sizeof(pa0x) != sizeof(a) );













    void f( float x[10], float *y ) {
        static_assert( sizeof(x) == sizeof(void*) );
        static_assert( sizeof(y) == sizeof(void*) );
    }
    f(0,0);















    // reusing local var `float a[10];`
    float v;
    f(  a,  a ); // ok: two decays, one into an array spelling
    f( &v, &v ); // ok: no decays; a non-array passes to an array spelling
















    char ca[] = "hello";    // array on stack, initialized from read-only data
    char *cp = "hello";     // pointer to read-only data [decay here]
    void edit(char c[]) {   // param is pointer
        c[3] = 'p';
    }
    edit(ca);               // ok [decay here]
    edit(cp);               // Segmentation fault
    edit("hello");          // Segmentation fault [decay here]












    void decay( float x[10] ) {
        static_assert( sizeof(x) == sizeof(void*) );
    }
    static_assert( sizeof(a) == 10 * sizeof(float) );
    decay(a);

    void no_decay( float (*px)[10] ) {
        static_assert( sizeof(*px) == 10 * sizeof(float) );
    }
    static_assert( sizeof(*pa) == 10 * sizeof(float) );
    no_decay(pa);
}
