In the early days, K&R C didn't even let you pass structs by value. The only ways to create a copy was via memcpy()
(or your own implementation of it). ISO C then defined copying and assignment, but conventional wisdom was that you really wanted to avoid copying data around: Memory access is expensive.
That principle is even "truer" today, but the conclusions we draw from it have been turned on their head: We sometimes copy more explicitly to avoid unnecessary implicit "read-throughs" all the way to the RAM. The reason is that modern cores have caches which can be accessed with much lower latency than the RAM proper, and computation has become very cheap. We want to make sure the cache contents is independent and does not need expensive refreshes/write-throughs.
With parallel processing and multi core CPUs, it turns out that aliasing (accessing the same memory through different identifiers, which is what you do with a pointer) prevents independent operations on local cached copies of that memory because a different thread or core may have written to it. Synchronizing the cache carries a comparatively large cost.
If each core or thread can operate on their own local data copy they don't need to wait and can focus on the task at hand, so to speak. The benefit of this independence tends to outweigh the cost of the initial, explicit copying to an astonishing degree. Functional languages which essentially move copies of data around have received more attention recently exactly because their paradigm essentially makes a program appear as a collection of data-independent tasks, which makes parallelization easier to a degree which even allows automatic parallelization.
Bottom line: Even in a single-threaded program written in an imperative language like C, working on copies of data may allow the compiler to generate more efficient code which may outweigh the penalty for the explicit copying in the first place.