You might consider using TEA or its successor, XTEA. Here's the complete C source code for XTEA, taken from the Wikipedia article:
#include <stdint.h>
/* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */
void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
for (i=0; i < num_rounds; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
}
v[0]=v0; v[1]=v1;
}
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;
for (i=0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0]=v0; v[1]=v1;
}
This code is simple enough that your students should be able to easily integrate it into their programs, and even modify it if necessary. You might even want to consider reusing it for other exercises, too. Notably, it also involves no special pre-processing of the key — the "key schedule", such as it is, is very simple and done directly within the encryption loop.
One feature of (X)TEA that (while generally a good thing) may not be ideal for your purposes is that it has a 128-bit keyspace, which is too large for a practical brute force search. For your exercise, you could artificially restrict the keyspace to just, say, 32 bits by setting the remaining 96 bits of the key to some fixed value. Then compositing two such encryptions with different keys should give you a 64-bit keyspace, which is still rather large to just exhaustively search by brute force, whereas the meet-in-the-middle attack needs only up to 233 operations, which should be easily doable.
By the way, the general property you're asking for is called key agility. You may find other suitable ciphers by Googling for "key-agile cipher".