Yes, very good programmers can make mistakes.
To meet your challenge, think about the problem. How about this?
file size + 1 => s
allocate char buffer b[s]
read file to b (all data must be in memory, or merge sort. if on linux and allocation worked, read may fail! oom will get us, or we bail on read failure)
add final newline if missing
count newlines => n
allocate line pointers p[n] (if line pointers will not fit, we bail -- we could use offsets and fancy virtualization, if this is not a Z80)
fill pointer array p
sort => sorted[n] (if sorting fails, bail)
output sorted lines
Same for C and C++. UTF-8 is ok.
Do you want more data than will fit into memory? Even then,
C++ doesn't bring much to the table. Separating the sort algorithm? Yes C++ BEGINs to pull ahead by a bit.
safe? yes. easy to write? yes. no fancy bits? yes.
Transcribe to C C++ as you will. Java? won't be as pretty. Rust, Go? don't know.
Javascript. Not even close.
Since this is a "beginning programmer" problem, give a design that works for another language that makes sense to a beginning programmer.