Paul covered the most important points. This answer is intended to be a
complement to his.
First, you should keep in mind the general rules, which are more
important than the more specific ones. The general rule for saving RAM
is: be aware of what you are storing, and do not store anything you do
not really need. The general rule for saving flash is: be aware of what
you are doing, and do not do anything you do not really need.
Now, a few specific tips:
const qualifier for declaring constants (e.g.
const int ledPin = 13;). The compiler will optimize-out the storage of
the constant and use immediate addressing instead.
PROGMEM for arrays of constants.
Whenever possible, use static memory (globals and
rather than heap allocation (
new). This will prevent
memory fragmentation and make the memory usage more predictable (only
the stack holds dynamic memory): you know at compile time, rather than
run time, whether you are low in RAM.
For the same reason, prefer C strings (
char *) over
Use the C99 types
uint8_t whenever 8 bits are enough for
your integer variables.
static qualifier for functions that will be used only in the
same source file, especially for functions that are called only from one
place. This gives the compiler more optimization opportunities.
If you need to optimize,
avr-nm to know what is
consuming your precious RAM.