URL percent encoding function
First of all, URL encoding is more nuanced than you might think.  Be cautious when applying encoding.

As for your code, the only blatant bug I see is that it can segfault when encoding a non-ASCII string.  The -length method returns the number of Unicode characters in the string.  Since you are working one char at a time, you need the number of bytes instead.

NSUInteger clen = [orig lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger nlen = 3 * clen;


It would be better to change the method signature to:

NSString *urlEncode(const NSString *orig)


I think that using a for loop would improve readability.  Currently, you declare/initialize *o, test it, and decrement it on three separate lines.  A for loop would provide an instantly recognizable structure to make it obvious how those three lines of code are related:

for (const char *o = cstr + clen - 1; o &gt;= cstr; o--) {
    unsigned char c = *o;
    if (safe[c]) {
        *--p = c;
    } else {
        *--p = digits[c &amp; 0x0f];
        *--p = digits[c &gt;&gt; 4];
        *--p = '%';
    }
}


The null char would be better written as '\0'.

Personally, I would choose to iterate forward rather than backward through the string, as it simplifies the loop by a few instructions, and is easier to understand.  It also gives you the option of calling -maximumLengthOfBytesUsingEncoding (which runs in O(1) time) instead of -lengthOfBytesUsingEncoding.

unsigned char c;
char *p = newstr;
for (const char *o = cstr; (c = *o); o++) {
    ...
}