Arrays are not pointers. Pointers are not arrays.
Perhaps it would be clearer to say that array objects are not pointer objects, and vice versa.
When you declare int *arr, arr is a pointer object. That's all it is; it cannot be, and never will be, an array.
When you execute arr = malloc(10 * sizeof *arr);, (if malloc() doesn't fail, which you should always check), arr now points to an int object. That object happens to be the first element of a 10-element array of int (the one created by the malloc call). Note that there is such a thing as a pointer to an array, but this isn't it.
Arrays, in a very real sense, are not first-class types in C. You can create and manipulate array objects as you can with any other type of objects, but you'll rarely deal with array values directly. Instead, you'll deal with the elements of an array object indirectly, via pointers to those elements. And in the case of the arr declaration above, you can perform arithmetic on the pointer to the first element to obtain pointers to the other elements (and you have to have some other mechanism to remember how many elements there are).
Any expression of array type, in most contexts, is implicitly converted to a pointer to the array's first element (the exceptions are: the operand of a unary & operator, the operand of the sizeof operator, and a string literal in an initializer used to initialize an array (sub)object). That's the rule that makes it seem as if arrays and pointers are interchangeable.
The array indexing operator [] is actually defined to work on pointers, not arrays. a[b] is simply another way of writing *((a)+(b)). If a happens to be the name of an array object, it's first converted to a pointer, as I describe above.
I highly recommend reading section 6 of the comp.lang.c FAQ. (The link is to the front page, not directly to section 6, because I like to encourage people to browse the whole thing.)
I mentioned that there are array pointers. Given int foo[10];, &foo[0] is a pointer to an int, but &foo is a pointer to the entire array. Both point to the same location in memory, but they're of different types, and they behave quite differently under pointer arithmetic.