I know that this is fixed when you use %lf when scanning, but why does this happen when using %f?
The difference between printf and scanf function arguments is that you pass values to printf, but to scanf you pass pointers (i.e. addresses of values). According to C rules, when a function takes a variable number of arguments, all parameters undergo default promotions.
One of the promotions is that floats get converted to double, in the same way that shorts get converted to int. That is why you can use %f or %lf with printf: both types of values are converted by the compiler to double, so accessing them is safe.
However, there is no such rule for pointers (and for a good reason: trying to write a double into a space of float would be undefined behavior). That is why you must differentiate between %f and %lf when passing parameters to the scanf family of functions.