a library
When you need to sort a list, talk to a network, or do trigonometry, you almost never write that code yourself from scratch — someone has already written, tested, and packaged it. A library is exactly that: a reusable collection of already-compiled code, plus a way to call into it, that many different programs can share. It is the systems-programming equivalent of a cookbook full of recipes you can drop into your own kitchen.
Concretely, a library bundles up a set of functions (and sometimes data) that solve some problem, such as the C standard library's printf and malloc, or a math library's sin and sqrt. You do not copy its source into your project; instead your program is built to call those functions, and the library's compiled machine code is joined to your program either when you build it or when you run it. A library has two faces: a header file that declares what you can call (the names, parameters, and return types) and the compiled code that actually implements those calls.
Why it matters: libraries are how software is built out of reusable parts instead of reinvented every time, which saves enormous effort and concentrates bug-fixing and optimization in one shared place. Libraries come in two flavors that behave quite differently — static libraries, copied into your program at build time, and dynamic (shared) libraries, loaded alongside your program when it runs — and understanding that split is most of what 'linking against a library' is about.
#include <math.h> // the library's interface (header) ... double r = sqrt(2.0); // call into the math library Build: gcc main.c -lm // -lm links the math library's code
You include the header to call the functions, and link the library so its compiled code is attached.
Including a library's header only gives you its declarations. If you forget to link the actual library (e.g. -lm for the math library), the compile succeeds but the linker fails with 'undefined reference' — a sign the interface was found but the implementation was not.