user43127: Though I've written C/C++ code for a long time, the unseen limitations on how memory was consumed on various MCU and SOC programming platforms have often tripped me up. As I'm about to build up code for my first large project for my NANO boards, which will likely use a fair amount of its resources, I'd like to be better prepared for any surprising and unexpected "gotchas" to look out for. 
For example, on another SOC I recently worked on extensively (The Pololu.com wixel) I was very surprised to learn that function/method arguments and auto variables, which I'd normally expect to be stack allocated and recovered when a function returns were in fact permanently allocated for the life of the program! Wow! so on that platform, where I'd normally hate to "overwork" variables or reuse variables after their names no longer make sense, I had to adjust my coding to what I'd normally consider BAD for readability. Not to mention realizing that simple loop variables were better off allocated globally. Yecch!
Can those of you who have run into such unexpected coding issues in the Arduino environment share some "special" guidelines about things like this? 

user30700: Edgar's got some great tips, and I'll reiterate one before giving a few more: 
avoid dynamic memory allocation
Don't use malloc. When you're designing a system, budget out your RAM like you do your monthly budget. Make sure you're able to do everything at once. 
And a couple other tips:
global statics
Make full use of the BSS block; try to block out space for as much as possible in global static arrays. You may shudder or scoff at the idea of putting everything at a global level, but embedded is a paradigm shift, with its own set of rules.
Since you'll have so many variables at a global level, static helps you to avoid polluting your namespace too much.
avoid fancy C++ features
In fact, try to not use C++ at all. C++ takes you "farther from the metal," with its RAII and its constructors and its implicit type conversion... It's much harder to keep a tight inventory of all of your resources when your language does so much behind the scenes. If you really want to use a certain C++ language feature, try to keep the tone of your code more like "C with bits of C++" rather than "C++ shoehorned into an embedded system." That never goes well.
Especially avoid generics/templates, which will eat up lots of your memory. Every time you use a new type with a template in your code, another copy of the template class is compiled into your program, just for that one type. Ever wonder why C++ binaries can balloon to 20, 50, even 100 MB? Templates, man. Templates.
const
This keyword should go on as many variables as it can. Keeping this habit will save on both execution time and space consumption. Learn the difference between const T* foo, T* const foo, and const T* const foo.

user7508: As you have noticed yourself, this can be somewhat platform-dependent.
Since you are working on a Nano, my answer will be for the AVR
architecture, when compiled with gcc, the avr-libc, and the Arduino core
library.
First, let me reassure you: this weird behavior you saw of the Wixel
doesn't happen on this platform. Local variables get allocated mostly in
CPU registers, then on the stack.
Now, the first general rule may sound obvious: think twice about what
your program really needs to remember. Also, use each time the
smallest possible data type. The C99 types int8_t, uint16_t and co.
are useful for this.
Another rule you will often hear on this platform: avoid dynamic
allocation, i.e. malloc() and new, as quite often you cannot afford
heap fragmentation. Avoid also the String class, as it relies on
dynamic allocation. Prefer when possible static allocation, or stack
allocation for small things.
Don't forget to use const for constants: with this qualifier the
compiler can often optimize the constants out as immediate operands. For
arrays of constants, use PROGMEM. Yes, it's not comfortable
to use, but it can save you lots of RAM. The F() macro for printing
constant messages is a special case of PROGMEM.
Lastly, be very careful with recursion.

43127: <p>Though I've written C/C++ code for a long time, the unseen limitations on how memory was consumed on various MCU and SOC programming platforms have often tripped me up. As I'm about to build up code for my first large project for my NANO boards, which will likely use a fair amount of its resources, I'd like to be better prepared for any surprising and unexpected "gotchas" to look out for. </p>

<p>For example, on another SOC I recently worked on extensively (The Pololu.com wixel) I was very surprised to learn that function/method arguments and auto variables, which I'd normally expect to be stack allocated and recovered when a function returns were in fact permanently allocated for the life of the program! Wow! so on that platform, where I'd normally hate to "overwork" variables or reuse variables after their names no longer make sense, I had to adjust my coding to what I'd normally consider BAD for readability. Not to mention realizing that simple loop variables were better off allocated globally. Yecch!</p>

<p>Can those of you who have run into such unexpected coding issues in the Arduino environment share some "special" guidelines about things like this? </p>
 30700: <p>Edgar's got some great tips, and I'll reiterate one before giving a few more: </p>

<p><strong>avoid dynamic memory allocation</strong></p>

<p>Don't use malloc. When you're designing a system, budget out your RAM like you do your monthly budget. Make sure you're able to do everything at once. </p>

<p>And a couple other tips:</p>

<p><strong>global statics</strong></p>

<p>Make full use of the BSS block; try to block out space for as much as possible in global <code>static</code> arrays. You may shudder or scoff at the idea of putting everything at a global level, but embedded is a paradigm shift, with its own set of rules.</p>

<p>Since you'll have so many variables at a global level, <code>static</code> helps you to avoid polluting your namespace too much.</p>

<p><strong>avoid fancy C++ features</strong></p>

<p>In fact, try to not use C++ at all. C++ takes you "farther from the metal," with its RAII and its constructors and its implicit type conversion... It's much harder to keep a tight inventory of all of your resources when your language does so much behind the scenes. If you really want to use a certain C++ language feature, try to keep the tone of your code more like "C with bits of C++" rather than "C++ shoehorned into an embedded system." That never goes well.</p>

<p>Especially avoid generics/templates, which will eat up lots of your memory. Every time you use a new type with a template in your code, another copy of the template class is compiled into your program, just for that one type. Ever wonder why C++ binaries can balloon to 20, 50, even 100 MB? Templates, man. Templates.</p>

<p><strong>const</strong></p>

<p>This keyword should go on as many variables as it can. Keeping this habit will save on both execution time and space consumption. Learn the difference between <code>const T* foo</code>, <code>T* const foo</code>, and <code>const T* const foo</code>.</p>
 7508: <p>As you have noticed yourself, this can be somewhat platform-dependent.
Since you are working on a Nano, my answer will be for the AVR
architecture, when compiled with gcc, the avr-libc, and the Arduino core
library.</p>

<p>First, let me reassure you: this weird behavior you saw of the Wixel
doesn't happen on this platform. Local variables get allocated mostly in
CPU registers, then on the stack.</p>

<p>Now, the first general rule may sound obvious: think twice about what
your program <em>really</em> needs to remember. Also, use each time the
smallest possible data type. The C99 types <code>int8_t</code>, <code>uint16_t</code> and co.
are useful for this.</p>

<p>Another rule you will often hear on this platform: avoid dynamic
allocation, i.e. <code>malloc()</code> and <code>new</code>, as quite often you cannot afford
heap fragmentation. Avoid also the <code>String</code> class, as it relies on
dynamic allocation. Prefer when possible static allocation, or stack
allocation for small things.</p>

<p>Don't forget to use <code>const</code> for constants: with this qualifier the
compiler can often optimize the constants out as immediate operands. For
arrays of constants, use <a href="https://www.arduino.cc/reference/en/language/variables/utilities/progmem/" rel="nofollow noreferrer"><code>PROGMEM</code></a>. Yes, it's not comfortable
to use, but it can save you lots of RAM. The <code>F()</code> macro for printing
constant messages is a special case of <code>PROGMEM</code>.</p>

<p>Lastly, be very careful with recursion.</p>
