Let's have this array:
char arr[SIZE_MAX];
Note that many C implementations will reject that, SIZE_MAX being larger than any array they can actually support.  SIZE_MAX is the maximum value of type size_t, but that's not the same thing as the (implementation-dependent) maximum size of an object.
And I want to loop through it (and one past its last element):
for (i = 0; i <= sizeof(arr); i++)
What is the most adequate type for i?
There is no type available that we can be confident of being able to represent SIZE_MAX + 1, and supposing that arr indeed has size SIZE_MAX, you need i's type to be able to represent that value in order to avoid looping infinitely.  Unless you want to loop infinitely, which is possible, albeit unlikely.
On the other hand, if we have
char arr[NOT_SURE_HOW_LARGE_BUT_LESS_THAN_SIZE_MAX];
then the appropriate type for i is size_t.  This is the type of the result of the sizeof operator, and if the only assumption we're making is that the object's size is smaller than SIZE_MAX then size_t is the only type we can be confident will serve the purpose.
If we can assume tighter bounds on the object's size, then it may be advantageous to choose a different type.  In particular, if we can be confident that it is smaller than UINT_MAX then unsigned int may be a slightly more performant choice.  Of course, signed types may be used for i, too, provided that they can in fact represent all the needed values, but this may elicit a warning from some compilers.