Runtime-sized allocation of arrays is legal in C99 (but not in the older C89 standard, which some badly-maintained compilers might still constrain you to); the popular gcc has long implemented it as a non-standard extension.
malloc still has the advantage that the memory can be deallocated (with free) exactly when you want it to be -- so you can usefully return a malloced array as your function's result, and the caller will free it when done with it. Runtime-sized arrays' lifetime is determined by lexical scope -- handy when it works for you, but an excessive constraint sometimes;-).
Of course, style-guides that constrain malloc and free to happen within the same function would give up on this crucial difference. There are others, though, such as the ability to realloc a malloc-ed array if you need to change its size (which also doesn't apply to runtime-sized arrays).