int a[2]; means "allocate memory that is 2 * sizeof(int)"
a[5] is syntactic sugar for *(a + 5), which point to an area of memory a + (5 * sizeof(int)). So 3 * sizeof(int) past the end of your array. Where is that? Who knows?
Some languages do bound checking, and I have heard of some C compilers that can do it as well, but most do not. Why not do bound checking? Performance. And performance is a major reason for using C in the first place. But that's OK, because C programmers are good programmers and never go beyond the bounds of an array. (hopefully)