Each reference you create takes more memory overhead.
I try to keep those references as comments, as the example below.
This is a read-only situation, but a write could easily be done with an or.
Just my opinion but this is way to much complication for such a tiny device.
// Update a single digit to the display buffer
void digit_on(uint8_t digit_pixels[], uint8_t x_offset) {
// 4 sets, 2 rows per, 8 rows total
for (index = 0; index < 4; index++) {
// Contains 2 rows, one per nibble
// Upper row in MS nibble
// Lower row in LS nibble
// 0bUUUULLLL
rows = digit_pixels[index];
// Upper Row
x = x_offset; // adjust digit position on screen
y = index + index; // 2k, even row
// color shift Modulo 8
color_y = (y + color_shift) & 0b00000111;
if (rows & 128) leds[pos[y][x]] = font_color[color_y]; // check b2^7
x++;
if (rows & 64) leds[pos[y][x]] = font_color[color_y]; // check b2^6
x++;
if (rows & 32) leds[pos[y][x]] = font_color[color_y]; // check b2^5
x++;
if (rows & 16) leds[pos[y][x]] = font_color[color_y]; // check b2^4
// Lower Row
x = x_offset; // reset x
// 2k+1 Modulo 8
y++;
color_y = (y + color_shift) & 0b00000111;
if (rows & 8) leds[pos[y][x]] = font_color[color_y]; // check b2^3
x++;
if (rows & 4) leds[pos[y][x]] = font_color[color_y]; // check b2^2
x++;
if (rows & 2) leds[pos[y][x]] = font_color[color_y]; // check b2^1
x++;
if (rows & 1) leds[pos[y][x]] = font_color[color_y]; // check b2^0
}
}