rd, off(rs1)rd = mem[rs1 + off]lh loads a halfword from memory. Memory is measured in bytes — a byte is 8 bits, the smallest individually addressed unit. A full word is 4 bytes (32 bits); a halfword, as the name says, is half of that: 2 bytes, or 16 bits. lh reads 16 bits from memory rather than the full 32 that lw reads. It uses the same lh rd, offset(rs1) addressing as lw (base register plus a constant offset; see the lw page if that form is new).
But a register is always 32 bits, so loading only 16 raises a question: what fills the other 16? lh does something called sign-extension. It looks at the top bit of the 16-bit value — the bit that marks the sign in a signed number — and copies it into all 16 upper bits of the register. This preserves the number's value and sign, so a 16-bit -3 arrives as a proper 32-bit -3.
That makes lh the correct load for *signed* 16-bit data, such as audio samples or sensor readings that can go negative. Its partner lhu (the u for unsigned) fills the top with 0s instead, which is right for data that is never negative. The contrast is stark: the bit pattern 0x8000 loaded with lh becomes -32768, but with lhu becomes +32768 — same bits in memory, different meaning depending on which load you choose.
Because halfwords are 2 bytes, arrays of them sit at offsets 0, 2, 4, and you step a pointer through them by adding 2.