Pointer vs array in C, non-trivial difference

Please forgive me if i overlook anything in your analysis. But i think the fundamental bug in all that is this wrong assumption

type2_p->ptr has type "pointer to int" and the value is the start address of my_test.

There is nothing that makes it have that value. Rather, it is very probably that it points somewhere to

0x00000001

Because what you do is to interpret the bytes making up that integer array as a pointer. Then you add something to it and subscript.

Also, i highly doubt your casting to the other struct is actually valid (as in, guaranteed to work). You may cast and then read a common initial sequence of either struct if both of them are members of an union. But they are not in your example. You also may cast to a pointer to the first member. For example:

typedef struct {
    int array[3];
} type1_t;

type1_t f = { { 1, 2, 3 } };

int main(void) {
    int (*arrayp)[3] = (int(*)[3])&f;
    (*arrayp)[0] = 3;
    assert(f.array[0] == 3);
    return 0;
}

An array is a kind of storage. Syntactically, it's used as a pointer, but physically, there's no "pointer" variable in that struct — just the three ints. On the other hand, the int pointer is an actual datatype stored in the struct. Therefore, when you perform the cast, you are probably* making ptr take on the value of the first element in the array, namely 1.

*I'm not sure this is actually defined behavior, but that's how it will work on most common systems at least.


Where is my reasoning wrong/what do I not understand?

type_1::array (not strictly C syntax) is not an int *; it is an int [3].

How do I declare type2_t to make ptr point to the first member of the array?

typedef struct 
{    
    int ptr[];
} type2_t;

That declares a flexible array member. From the C Standard (6.7.2.1 paragraph 16):

However, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array.

I.e., it can alias type1_t::array properly.