The results you expect only hold as long as you are within the bounds of a[2][3][2]. That is, when you do a[0][0][0] up to a[1][2][1], your assumptions will hold. But once you cross that boundary, the results you see are no longer the same.
What is actually happening here is that a[i][j][k] is technically the same as k+j*2+i*2*3 elements after the first, considering the numbers you used in your code. This makes it possible to have a representation of your array that looks "3D" but actually in memory they are "in line" or in a one-dimensional array. So by doing this *2 and *2*3 you are actually jumping to the "next" sub-array.
Why doesn't it work when you get out of the bounds of a[2][3][2]? Take for example for a[i][j][k] with k=4, it will be equivalent to i*2*3 + j*2 + k = i*2 + (j+1)*3 + 1. So it's as if it had "jumped" to the next row/column/whatever.
You can visualize this better on a 2-dimensional array by imagining a table and going through the row and once you beyond the last column of the row, you fall on the row below it.
However, C does not warn you when you go out of the bounds of your multidimensional array, or when you "fall" off the row you're on.
Update
You are right in saying a[0][5][0] does not exist. What happens in this case is that you will actually read something else which is in memory, right next to a. So for example, let's say you have a and b in your code, when you are dealing with a and b in your code, what is going on under the hood is that a and b are just some chunk of memory. And let's say a is an array with 12 elements in total, when you get outside of these 12 elements, C will just assume the array is as big as you say it is, and go fetch the piece of memory that's after 15 "chunks" and will give it to you. So a[15] actually exists but it does not belong to the array. It might belong to b if they are next to each other on memory or it can belong to something else entirely.
The technical terminology is that when you declare a as an array of size 12 integers, it will allocate the memory of 12 integers (12 * 4 bytes) next to each other and label that as a for you. a will point to the beginning of that piece of memory; it's a pointer. When you do a[x] or a[i][j][k] you will get a pointer to the x-th piece of memory of a. And if x is greater than 12, it'll go outside of a and grab whatever was lying there and consider it is an integer. (while it could be something else; that's why you might get garbage when you do this kind of thing, because it might actually be something else and they interpret it as if it was an integer).
int a[2][3][2]different thanint a[12]?