Most memory efficient way to program
That is an incredibly hard question to give a definitive answer to. 

In general using OO consumes more memory, but that is the price you pay for greater flexibility and ease of use. The difference is usually minor though. Variables within an object take the same amount of space as variables outside an object. It's just the overhead of instantiating the object itself that adds to the memory usage, and that can be quite small, depending of course on what the object does.

Calling functions increases memory use on the stack. Every time you call a function the return address and a number of the internal CPU registers, along with some of the parameters, get placed on the stack. The deeper your function calls go the bigger the stack gets. But that is all temporary - as you leave the functions the stack shrinks again.

However, this is where it gets more complex:

The compiler performs optimizations. One of them is to consider functions for inlining. This replaces the function call with the content of the function that is being called. It makes for a slightly larger program, but it's a program that runs faster and uses less stack.

In your first two examples, because there is only one call to the blinkLed() function, the compiler will see that as a good candidate for using inline. So your first and second programs may well both end up exactly the same. 

There are times, as well, where variables that you declare don't actually ever exist. For instance, if you use a couple of temporary variables to do a few calculations in a function and then return the result the compiler may instead just use CPU registers to store the temporary values instead of allocating variable space in memory.

So it is very hard to say "this is better" or "that is better". Instead you should pay more attention to how and where you declare and use your variables.

In general there are two rules:


Keep your variables the smallest size possible for the contents (use 8 bit variables instead of int for storing smaller numbers).
Keep the scope of variables as small as possible.


The latter is often overlooked. The scope of a variable is the block (delimited by { and } for example) where the variable is declared. Anything inside that block, including sub-blocks, can see the variable. By keeping the variable in as small a scope as possible you increase the chances that the compiler will choose to use CPU registers instead of allocating memory.  For example:

int i;

for (i = 0; i &lt; 1000; i++) {
    .... do something ....
}

.... other things ....

for (i = 30; i &lt; 2000; i++) {
    .... do something else ....
}


That is pretty much guaranteed to allocate memory for i.  However:

for (int i = 0; i &lt; 1000; i++) {
    .... do something ....
}

.... other things ....

for (int i = 30; i &lt; 2000; i++) {
    .... do something else ....
}


With that method the variable i will only exist within the first loop, after which it disappears. It is then recreated as an entirely new variable for the second loop. It doesn't need to stay in memory in between. The compiler may just place it in internal registers, or it may reuse the same block of memory, etc.

Also by keeping scope as small as possible you increase the ability of the compiler to re-use the same bits of memory for different purposes. 10 integers in different scopes doesn't mean 20 bytes of memory - it may mean just 2 bytes for all 10 integers.

So as you can see managing memory effectively can be a bit of a black art at times.