Use bounds checking on input and avoid dangerous functions such as gets; choose safer equivalent functions that check boundary errors. Use abstraction libraries to hide risky APIs, while recognizing that this is not a complete solution.
As defense in depth, enable compiler or compiler-extension protections such as Microsoft Visual Studio /GS, Fedora/Red Hat FORTIFY_SOURCE, StackGuard, or ProPolice. These canaries and range or index checks detect some overflows, but they do not cover every type and the usual response can still be application termination and denial of service.
As additional defense in depth, use Address Space Layout Randomization (ASLR), Position-Independent Executables (PIE), and, where applicable, module rebasing or prelinking to make executable and library addresses less predictable. These measures do not provide a complete solution because address disclosures and side-channel attacks may bypass ASLR, and ASLR for libraries cannot be used together with prelinking.