Split a string and write the i-th element into a buffer with C Question
Recently I've written the following splitv() function, without using strtok. Any way to make it shorter and more efficient?
Descrption
The function calculates the index-th element of the string str split by delim. The element is written into buff and 0 is returned. When an index error is occurred, any non 0 value is returned. This function was inspired by the python split function: buff = str.split(delim)[index], but I think it works too hard and can be improved.
int splitv(char buff[], char str[], char delim[], int index) {
    // returns 0 if an element is written. Else non 0.
    char *start = str, *end;
    int i = 0, buff_i = 0;
    // check if delim not in str
    if ((end = strstr(str, delim)) == NULL) {
        if (index == 0) strcpy(buff, str);
        return index;
    }
    // delim is in str
    for (i = 0; i &lt; index; i++) {
        start = end + strlen(delim);
        end = strstr(start, delim);
        if (end == NULL) {
            // reached the last element
            if (i == index - 1) {
                end = str + strlen(str);
                break;
            }
            // index error: index &gt;= elements_count
            return -1;
        }
    }
    // copy element to buffer
    while (start != end) {
        buff[buff_i] = *start;
        start++;
        buff_i++;
    }
    buff[buff_i] = '\0';
    return 0;
}

Thanks in advance!
Before we talk about improving the efficiency of your function, lets talk about safety:

You never check the validity of your function parameters.
You have no way of knowing how big buff is.

For the first issue, if str or delim is null, passing them directly in to strstr will cause a segfault and crash your program.
The second issue is worse: if buff is smaller then str, your function may end up clobbering memory when it tries to copy from str to buff.
This is undefined behavior, and the results are unpredictable.
Now for some efficiency suggestions:

Calculate string length only once.
Since strlen works by running over the string looking for '\0' terminator, it is more efficient to call it only once at the beginning of your function and store the result in a variable.
This can also allow you to implement a simple shortcut for edge cases such as where str or delimiter are empty strings, or delimiter is longer then str.

You don't need your own while loop at the end and the buff_i variable.
You can simply use memcpy or strncpy to copy the element in to the buffer.
memcpy would be slightly more efficient, since it does not check for '\0', while strncpy does.

Since your logic is that if delimiter is never found, but the requested element is 0 the result is &quot;success&quot;, you don't need to handle this as a separate edge case.
That means you can get rid of the first if block, and handle everything in one loop.
You can also get rid of the special checks in the if loop and just focus on the search.


The following code example does not include the suggested validity checks:
int i;
char *start = str;
char *end = start;
size_t delim_len = strlen(delim);
size_t copy_len;

for (i = 0; i &lt;= index &amp;&amp; end != NULL; i++) {
    end = strstr(start, delim);
    if (end != NULL &amp;&amp; i != index) start = end + delim_len;
}

/* element not found */
if (i != index) return index;

if (end == NULL) {
    copy_len = strlen(start);
} else {
    copy_len = (ssize_t)(end - start);
}

memcpy(buff, start, copy_len);
buff[copy_len] = '\0';

return 0;