Righe come queste

ret[elem -1] = (char *)malloc(strlen(tmp) * sizeof(char));
ret[elem -1] = tmp;

non hanno senso. Assegni due valori diversi uno dopo l'altro allo stesso elemento, creando un memory leak ...
Ok ho fatto dei miglioramenti anche riscrivendo il codice e ordinandolo un pò:

codice:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

char **explode(char sep, char *str);

int main (void)
{
    int i, i2;
    
    char **new;

    new = explode(',', "100,2,3,4,5,6,7,8,9,");
    
    printf("%s ", new[0]);
    printf("%s ", new[1]);
    return 0;
}

char **explode(char sep, char *str)
{
    int elem = 0
      , i    = 0
      , i2;

    char *tmp = NULL
      , **ret = NULL;

    ret = (char **)malloc(sizeof(char **) * (strlen(str)));
    for (; i < strlen(str); i++)
    {
        if (*(str + i) == sep || *(str + i) == '\n')
        {
            printf("\n- %s\n", tmp);
            
            ret[elem] = (char *)malloc(sizeof(char) * (strlen(tmp)));
            for (i2 = 0; i2 < strlen(tmp); i2++)
            {
                ret[elem][i2] = tmp[i2];
            }

            elem++;
            free(tmp);
            tmp = NULL;
        }
        else
        {
            /* Se è il primo ciclo alloca, altrimenti re-alloca uno spazio più grande */
            if (tmp != NULL) tmp = (char *)realloc(tmp, sizeof(char) * (strlen(tmp) + 1));
            else             tmp = (char *)malloc (sizeof(char) * 1);

            tmp[i] = *(str + i);
        } 
    }
    
    free(tmp);
    
    printf("\nElementi: %d\n", (elem + 1));
    
    return ret;
}
Però mi assegna solo il primo elemento (100), gli altri se li mangia... penso di fare casino con il free e l'assegnazione di NULL.