This way, arr gets dynamically allocated at runtime, so it can be of any size depending on the input n.

What you were originally doing (i.e. declaring arr[n] after recieving n via scanf: scanf("%d", &n); int arr[n];) is not a good idea because it makes use of Variable-Length Arrays, a feature of C that is not mandatory in the latest C standard.

You see, arr gets created at compile-time, and you normally can only initialize it with a constant expression known at compile-time, which n, a variable recieved as user input, obviously isn't. Variable-length arrays are a feature of the language that basically allows you to bypass this rule, i.e. they make you able to initialize an array to a length not known at compile-time. This has been standartized in C99, but was listed as "optional" as of C11.

What you did after that (int arr[n]; scanf("%d", &n);) is quite illogical because, well, you declare arr as an array of n integers before you recieve the value of n as user input, and, well, know its value. It prints garbage because n is originally initialized to an unspecified "garbage" value, and this is what your VLA's size becomes when you declare it:

int arr[n]; //n is garbage at this point, you have no idea how large arr will be!
scanf("%d", &n); //you got the value of n that you needed, but too late, alas!