Charles' answer is correct, except you don't need to copy the bytes in/out, you can just cast the pointer to the Struct type:
# access first element of array
s0 = Shared::Sembuf.new(ops[0])
s0[:sem_op] = 0x4321
# access second element of array
s1 = Shared::Sembuf.new(ops[1])
s1[:sem_op] = 0x1234
... etc
That way, reads/writes to Struct fields will directly update the pointer you allocated.