How do nested for loops work?
A for statement repeats everything between { and }, (or just the next line if there is no { and } a certain number of times.  It's not as simple as you might at first think, but it makes more sense if you write it out as a while loop explicitly.

For instance, for (a; b; c) { ... } could be re-written as:

a;
while (b) {
    c;
}


So if you had: 

for (int i = 0; i &lt; 100; i++) { 
    Serial.println(i);
}


it could be re-written as:

int i = 0;
while (i &lt; 100) {
    Serial.println(i);
    i++;
}


The two mean exactly the same thing.  A for has the three elements - initializer, comparison and iterator.  The initializer is run before the loop starts, the comparison is used to work out when the loop should finish, and the iterator is used to move through each iteration of the loop.

To re-write your specific example:

for(int r = 0; r &lt; 8; r++){
    for(int c = 0; c &lt; 8; c++){
        lc.setLed(0, r, c, HIGH);
    }
}


You would end up with:

int r = 0;
while (r &lt; 8) {
    int c = 0;
    while (c &lt; 8) {
        lc.setLed(0, r, c, HIGH);
        c++;
    }
    r++;
}


Now, if we were to do away with the loops altogether and write it all out longhand, what would it look like?  Well, let's start with the inner c loop.  That loops from 0 to 7 (while less than 8), so replacing that loop with 8 discrete calls to the function replacing c each time would end up with:

int r = 0;
while (r &lt; 8) {
    lc.setLed(0, r, 0, HIGH);
    lc.setLed(0, r, 1, HIGH);
    lc.setLed(0, r, 2, HIGH);
    lc.setLed(0, r, 3, HIGH);
    lc.setLed(0, r, 4, HIGH);
    lc.setLed(0, r, 5, HIGH);
    lc.setLed(0, r, 6, HIGH);
    lc.setLed(0, r, 7, HIGH);
    r++;
}


We could take it a step further and unroll the outer r loop.  A subset of what you would end up with would be like this (note, I have skipped a lot of the middle ones):

lc.setLed(0, 0, 0, HIGH);
lc.setLed(0, 0, 1, HIGH);
lc.setLed(0, 0, 2, HIGH);
lc.setLed(0, 0, 3, HIGH);
lc.setLed(0, 0, 4, HIGH);
lc.setLed(0, 0, 5, HIGH);
lc.setLed(0, 0, 6, HIGH);
lc.setLed(0, 0, 7, HIGH);
lc.setLed(0, 1, 0, HIGH);
lc.setLed(0, 1, 1, HIGH);
... skipped a lot ...
lc.setLed(0, 6, 6, HIGH);
lc.setLed(0, 6, 7, HIGH);
lc.setLed(0, 7, 0, HIGH);
lc.setLed(0, 7, 1, HIGH);
lc.setLed(0, 7, 2, HIGH);
lc.setLed(0, 7, 3, HIGH);
lc.setLed(0, 7, 4, HIGH);
lc.setLed(0, 7, 5, HIGH);
lc.setLed(0, 7, 6, HIGH);
lc.setLed(0, 7, 7, HIGH);


There would, of course, be 8 × 8 = 64 entries in there.

for loops can be used in lots of other fun ways too.  It's not just a simple "run this X number of times".  For instance, you can loop through a C string until you reach the NULL character at the end of the string:

for (char *p = str; *p != 0; p++) {
    ... do something with *p
}


You can iterate through the entries in a linked list:

for (struct mylist *scan = myListHead; scan; scan = scan-&gt;next) {
    ... do something to scan-&gt;whatever ...
}


You can even embed functions in there:

for (char c = 0; c != '\n'; c = Serial.read()) {
    ... Do something with character `c` until `c` is a line feed ...
}


As you can see for is an incredibly powerful and flexible tool that is often overlooked in favour of the more explicit while.