ownership of an allocation
When you allocate a block on the heap, someone eventually has to free it — exactly once, at the right time. But a block is just an address; the memory itself carries no label saying who is responsible. Ownership is the informal idea, agreed by the programmers, of which piece of code is responsible for freeing a given allocation. C does not enforce ownership at all; it is a discipline you keep in your head and your comments.
Think of a library book. A pointer can be passed around freely — many functions may read or write through it — but exactly one of them is the owner, the one obligated to return the book (free the block) when everyone is done. Borrowing a pointer means using it without taking responsibility to free it; passing ownership means you hand the pointer over and the receiver now owes the free, so you must not free it yourself. The bugs come from disagreement: if two parties both think they own a block, it gets freed twice (a double-free). If both think the other owns it, it never gets freed (a leak). If one frees while the other still holds the pointer, the holder now has a dangling pointer. Good C code makes the rule explicit, often in the function name or a comment: a function that returns newly allocated memory documents the caller now owns this, free it; a function that merely borrows says it does not take ownership.
This is exactly the problem that the Rust language turns into a compile-time rule: in Rust, ownership is tracked by the compiler, each value has one owner, and the memory is freed automatically when the owner goes out of scope. In C you get the same concept but none of the enforcement — which is why a clear, written ownership convention is one of the most valuable habits a C programmer can build.
/* Convention written into the signature/comment: */ char *make_name(void); /* returns a NEW block; CALLER owns and must free it */ void print_name(const char *name); /* BORROWS; does not free */
Ownership is a convention you document; C does not track it. Decide who frees, and say so.
Ownership in C is informal — the compiler does not check it. A single block must have one owner; sharing a pointer without agreeing who frees it is how leaks and double-frees are born.