I wanted to dust off my C skills, so I decided to write a couple string manipulation functions.I aimed for simplicity and safety. Performance was not a concern.Please be a thorough as you like. C is not my everyday language, so I might have madesome obvious mistakes. I would also appreciate extra attention to the test cases I've provided.Are they easy to understand and expand? Is coverage good enough?#include <stdio.h>#include <string.h>#include <assert.h>#include <stdbool.h>// Erases a part of the string's content, filling the end with null chars.// `startIndex` must be in a valid range inside this string. The char pointed by `startIndex` is included.// If `count` is less than 0 or greater than the string's length, erases until the end, starting at `startIndex`.// Does nothing if the string is empty or if `count` is zero.size_t strErase(char * str, size_t len, size_t startIndex, int count){    assert(str != NULL);    if (*str == '\0')    {        assert(len == 0); // This would indicate a parameter mismatch if not true.        return len;    }    // If the string is not empty, a length must be provided.    assert(len != 0);    assert(startIndex < len && Index out of range!);    // Do nothing in this case.    if (count == 0)    {        return len;    }    // Erase ALL till the end of the string, starting from `startIndex`, if `count` is not in range.    if (count < 0 || (size_t)count >= len)    {        memset(&str[startIndex], 0, len - startIndex);        return len - startIndex; // New length.    }    // Erase `count` chars from an arbitrary position:    size_t charsToMove = len - (startIndex + count) + 1; // Including the null terminator (+1)    memmove(&str[startIndex], &str[startIndex + count], charsToMove);    return len - count; // New length.}// Replaces a sequence of characters in a string by a single character.// `startIndex` must be in a valid range inside this string. The char pointed by `startIndex` is included.// If `count` is less than 0 or greater than the string's length, fills with `replaceWith` char starting at `startIndex`.// Does nothing if the string is empty or if `count` is zero.void strReplace(char * str, size_t len, size_t startIndex, int count, char replaceWith){    assert(str != NULL);    if (*str == '\0')    {        assert(len == 0); // This would indicate a parameter mismatch if not true.        return;    }    // If the string is not empty, a length must be provided.    assert(len != 0);    assert(startIndex < len && Index out of range!);    // Do nothing in this case.    if (count == 0)    {        return;    }    // Fill until end with the given char, starting at pos:    if (count < 0 || (size_t)count >= len)    {        memset(&str[startIndex], replaceWith, len - startIndex);        return;    }    int charsLeft = len - startIndex;    memset(&str[startIndex], replaceWith, (count <= charsLeft) ? count : charsLeft);}// Thin wrapper over strcmp(str1, str2) == 0 for the test cases.bool strEquals(const char * str1, const char * str2){    return strcmp(str1, str2) == 0;}void Test_strReplace(void){    // Replace end of string:    {        char s[] = Hello World;        strReplace(s, strlen(s), 5, 6, '+');        assert(strlen(s) == 11);        assert(strEquals(s, Hello++++++));    }    // Replace beginning of string:    {        char s[] = Hello World;        strReplace(s, strlen(s), 0, 6, '+');        assert(strlen(s) == 11);        assert(strEquals(s, ++++++World));    }    // Replace middle of string:    {        char s[] = Hello World;        strReplace(s, strlen(s), 3, 5, '+');        assert(strlen(s) == 11);        assert(strEquals(s, Hel+++++rld));    }    // Replace end with count overflow:    {        char s[] = Hello World;        strReplace(s, strlen(s), 5, 999, '+');        assert(strlen(s) == 11);        assert(strEquals(s, Hello++++++));    }    // Replace the whole string from the start:    {        char s[] = Hello World;        strReplace(s, strlen(s), 0, strlen(s), '+');        assert(strlen(s) == 11);        assert(strEquals(s, +++++++++++));    }    // Replace the whole string from the start with count overflow:    {        char s[] = Hello World;        strReplace(s, strlen(s), 0, 999, '+');        assert(strlen(s) == 11);        assert(strEquals(s, +++++++++++));    }    // Count equal to zero is a no-op:    {        char s[] = Hello World;        strReplace(s, strlen(s), 2, 0, '+');        assert(strlen(s) == 11);        assert(strEquals(s, Hello World));    }}void Test_strErase(void){    // Erase end of string:    {        char s[] = Hello World;        strErase(s, strlen(s), 5, 6);        assert(strlen(s) == 5);        assert(strEquals(s, Hello));    }    // Erase beginning of string:    {        char s[] = Hello World;        strErase(s, strlen(s), 0, 6);        assert(strlen(s) == 5);        assert(strEquals(s, World));    }    // Erase from the middle of the string:    {        char s[] = Hello World;        strErase(s, strlen(s), 3, 5);        assert(strlen(s) == 6);        assert(strEquals(s, Helrld));    }    // Erase end with count overflow:    {        char s[] = Hello World;        strErase(s, strlen(s), 5, 999);        assert(strlen(s) == 5);        assert(strEquals(s, Hello));    }    // Erase the whole string from the start:    {        char s[] = Hello World;        strErase(s, strlen(s), 0, strlen(s));        assert(*s == '\0');    }    // Erase the whole string from the start with count overflow:    {        char s[] = Hello World;        strErase(s, strlen(s), 0, 999);        assert(*s == '\0');    }    // Count equal to zero is a no-op:    {        char s[] = Hello World;        strErase(s, strlen(s), 2, 0);        assert(strlen(s) == 11);        assert(strEquals(s, Hello World));    }}int main(void){    Test_strReplace();    Test_strErase();    printf(Passed all tests!\n);}
Playing with strings
c;strings;unit testing
Asserts are good in the test cases, but not in the actual code. First, in a release version they are no-ops, so the release doesn't check anything. Second, they result in a program termination, which is a bit drastic.Interfaces are unclear. What is len? It may only represent the length of the character array (vs C string), i.e. you do not rely on a terminating 0, and this, in turn, annuls the claim that strErase is filling the end with null chars. If you do rely on a terminating 0, do not have len as a parameter, but calculate it.Treating negative count is a somewhat unorthodox. Normally (if allowed at all) it means count backwards, that is, erase a [startIndex + count, startIndex) range.