Minimalist context compressor
Symbolic Constants
This code could use some symbolic constants:
struct context {
    size_t freq[256];          /* char -&gt; frequency */
    unsigned char sorted[256]; /* index -&gt; char */
    unsigned char order[256];  /* char -&gt; index */
} table[256];

void init()
{
    opt_k = 3;

    for (int p = 0; p &lt; 256; ++p) {
        for (int i = 0; i &lt; 256; ++i) {
            table[p].sorted[i] = i;
            table[p].freq[i] = 0;
            table[p].order[i] = i;
        }
    }
}

The use of symbolic constants would make this code easier to write and maintain. For example if there was a symbolic constant for 256 the size of the table and the loop controls could be changed with a single line edit.
Global Variables
In the function init() above, it is obvious that global variables are being used, table is on global variable and opt_k is another global variable.
Global variables are generally considered a bad programming practice, they make the code hard to write, debug and maintain. They also make it very easy to introduce bugs.
In the C programming language if the program consists of multiple files, it is possible that global variables can cause the program not to link if they are declared in multiple files.
Using assert() in C
If at some point the code is going to be compiled for release using the optimizing feature of the compiler, then the assert() statements will be optimized away. If the error checking provided by the asserts is required it will be better to replace the asserts with if statements.