why arr[-2] gives value?

In c and c++ languanges arrays do not have negative index values. If you tried to print that then it is by coincidence that the program worked at all. One reason it may have worked for you is if you declared two integers just before you declared the array so that the program was actually looking at one of the two integers instead of the array. For example

int a;
int b;
int arr[5];
printf("%d", arr[-2]);

If the above does not crash when you run the program what will get printed is the value of variable a. But there is no guarentee that the program will do that either. Because C language does not support negative index values the result of the program is called undefined behavior.

Because most C implementations don't perform bounds checking when accessing an array. So when you give an index to an array, that index (multiplied by the size of the element type according to the rules of pointer arithmetic) will simply be added to the address where the array begins and the item at the resulting address will be accessed. If that address is one that you're allowed to access, it will give you a value. If it isn't, you'll get a segmentation fault.

That said accessing an array out of bounds is undefined behavior and anything could happen.

Also note that if arr is actually a pointer inside another array (e.g. int base_arr[] = {1,2,3,4,5}; int *arr = base_arr+2;), -2 might very well be a valid index. In that case arr[-2] will have a fully defined value (in the example I gave it would be 1).