1

How do you insert a string (source) into another string (dest) in C at a specific position, overwriting the destination string (instead of shifting the contents of the destination string at the insert position).

A function such as string_insert_and_replace abstracted below;

char str_dest[] = "abcdefg";
char str_source[] = "123";

//The 3rd argument is the position to insert at
string_insert_and_replace(str_dest, str_source, 3);

//str_dest should now be "abc123g"
cegfault
  • 6,442
  • 3
  • 27
  • 49
Rs Fps
  • 65
  • 1
  • 7
  • 1
    Just to be clear, do you want (e.g.) `replace("abcdefg","123",3);` to produce `abc123g`? – Craig Estey Jan 28 '19 at 01:02
  • @CraigEstey — looks like it from the comment. – Jonathan Leffler Jan 28 '19 at 01:04
  • it's easy enough if you imagine how to do it on paper. and there are a lot of duplicates: [Inserting char string into another char string](https://stackoverflow.com/q/2015901/995714), [Inserting String into String in C](https://stackoverflow.com/q/43215717/995714), [inserting a substring into another string in c](https://stackoverflow.com/q/36629795/995714)... – phuclv Jan 28 '19 at 04:09
  • Possible duplicate of [Inserting char string into another char string](https://stackoverflow.com/questions/2015901/inserting-char-string-into-another-char-string) – phuclv Jan 28 '19 at 04:09
  • No it's different as like I said I don't want the remaining characters to be right shifted. I wanted the characters to be overwritten. @CraigEstey yes. – Rs Fps Jan 28 '19 at 22:00
  • Use `memcpy`, but be sure you have enough space. – Neil Jan 29 '19 at 01:25

4 Answers4

0

Here's a version that works. I've included some unit tests as well:

#include <stdio.h>
#include <string.h>

char str_dest[] = "abcdefg";
char str_source[] = "123";

int dlen;

void
replace(char *dst,char *src,int pos)
{

    // find starting place in destination -- we must scan char-by-char in
    // case pos is larger than the destination string size
    for (;  (*dst != 0) && (pos > 0);  ++dst, --pos);

    // copy in source string until _it_ ends or we run out of room in the
    // destination
    for (;  (*dst != 0) && (*src != 0);  ++dst, ++src)
        *dst = *src;
}

void
test(int pos)
{
    char dst[dlen + 1];

    strcpy(dst,str_dest);
    replace(dst,str_source,pos);

    printf("POS: %d DST: '%s'\n",pos,dst);
}

int
main(void)
{

    dlen = strlen(str_dest);

    for (int pos = 0;  pos <= (dlen + 3);  ++pos)
        test(pos);

    return 0;
}

UPDATE:

I'm writing this code for a microcontroller, would the safety check affect performance?

Yes, the safety check requires that the destination string be scanned byte by byte to locate the end.

Note that there is no need to do strlen on the source string. See the string_replace_fast variation of your function below. It isn't any safer, but it is [approximately 2x] faster.

Also I think with this current code I am overwriting memory that doesn't belong to the dest string if the source string length plus the pos argument are greater than strlen(dest).

Yes, that is correct. You can see it in the test results below.

You may have to sacrifice a bit of speed. If this isn't a function that is called a lot, then go for the slower/safer version. You can only tell this with some benchmarking.

Here's a modified version of the test program that has benchmarking for your version and mine along with a variation or two:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

char str_dest[] = "abcdefghijklimnopqrstuvwxyz";
char str_source[] = "123";
char *tmp;

int dlen;

typedef void (*func_p)(char *dst,char *src,int pos);

#define TIMEIT(_fnc,_pos) \
    timeit(_fnc,_pos,#_fnc)

char *
fixstr(const char *src)
{
    static char fix[1000];
    char *dst = fix;

    for (;  *src != 0;  ++src) {
        if ((*src >= 0x20) && (*src <= 0x7E))
            *dst++ = *src;
        else
            dst += sprintf(dst,"{?%2.2X?}",*src & 0xFF);
    }
    *dst = 0;

    return fix;
}

double
tvgetf(void)
{
    struct timespec ts;
    double sec;

    clock_gettime(CLOCK_REALTIME,&ts);
    sec = ts.tv_nsec;
    sec /= 1e9;
    sec += ts.tv_sec;

    return sec;
}

void
string_replace_pos(char *dest, char *source, int pos)
{
    int source_length = strlen(source);

    for (int i = 0; i < source_length; i++) {
        dest[pos + i] = source[i];
    }
}

void
string_replace_fast(char *dest, char *source, int pos)
{
    int chr;

    dest += pos;
    for (chr = *source++;  chr != 0;  chr = *source++, ++dest)
        *dest = chr;
}

void
replace(char *dst,char *src,int pos)
{

    // find starting place in destination -- we must scan char-by-char in
    // case pos is larger than the destination string size
    for (;  (*dst != 0) && (pos > 0);  ++dst, --pos);

    // copy in source string until _it_ ends or we run out of room in the
    // destination
    for (;  (*dst != 0) && (*src != 0);  ++dst, ++src)
        *dst = *src;
}

void
replace2(char *dst,char *src,int pos)
{
    int mlen = strlen(dst);

    // find starting place in destination -- we must scan char-by-char in
    // case pos is larger than the destination string size
    if (pos <= mlen)
        dst += pos;

    // copy in source string until _it_ ends or we run out of room in the
    // destination
    for (;  (*dst != 0) && (*src != 0);  ++dst, ++src)
        *dst = *src;
}

void
timeit(func_p func,int pos,const char *name)
{
    double tvbeg;

    strcpy(tmp,str_dest);
    tvbeg = tvgetf();

    for (int iter = 1;  iter <= 1000;  ++iter)
        func(tmp,str_source,pos);

    tvbeg = tvgetf() - tvbeg; \

    printf("POS: %d %.9f DST: '%s' (%s)\n",
        pos,tvbeg,fixstr(tmp),name);

    int clen = strlen(tmp);
    if (clen != dlen)
        printf("ERROR: length mismatch -- EXPECTED: %d ACTUAL: %d\n",dlen,clen);
}

void
test(int pos)
{

    printf("\n");
    TIMEIT(string_replace_pos,pos);
    TIMEIT(string_replace_fast,pos);
    TIMEIT(replace,pos);
    TIMEIT(replace2,pos);
}

int
main(void)
{

    dlen = strlen(str_dest);
    tmp = malloc(dlen + 100);

    for (int pos = -3;  pos <= (dlen + 3);  ++pos)
        test(pos);

    return 0;
}

Here is the output of this test program.

Note the ERROR lines for your versions. Also, note what happens if the insertion position is negative.

POS: -3 0.000008106 DST: 'abcdefghijklimnopqrstuvwxyz' (string_replace_pos)
POS: -3 0.000003815 DST: 'abcdefghijklimnopqrstuvwxyz' (string_replace_fast)
POS: -3 0.000007629 DST: '123defghijklimnopqrstuvwxyz' (replace)
POS: -3 0.000011683 DST: 'abcdefghijklimnopqrstuvwxyz' (replace2)

POS: -2 0.000007153 DST: '3bcdefghijklimnopqrstuvwxyz' (string_replace_pos)
POS: -2 0.000003815 DST: '3bcdefghijklimnopqrstuvwxyz' (string_replace_fast)
POS: -2 0.000007391 DST: '123defghijklimnopqrstuvwxyz' (replace)
POS: -2 0.000012159 DST: '3bcdefghijklimnopqrstuvwxyz' (replace2)

POS: -1 0.000007391 DST: '23cdefghijklimnopqrstuvwxyz' (string_replace_pos)
POS: -1 0.000003815 DST: '23cdefghijklimnopqrstuvwxyz' (string_replace_fast)
POS: -1 0.000007391 DST: '123defghijklimnopqrstuvwxyz' (replace)
POS: -1 0.000012159 DST: '23cdefghijklimnopqrstuvwxyz' (replace2)

POS: 0 0.000007391 DST: '123defghijklimnopqrstuvwxyz' (string_replace_pos)
POS: 0 0.000004053 DST: '123defghijklimnopqrstuvwxyz' (string_replace_fast)
POS: 0 0.000007391 DST: '123defghijklimnopqrstuvwxyz' (replace)
POS: 0 0.000012159 DST: '123defghijklimnopqrstuvwxyz' (replace2)

POS: 1 0.000007391 DST: 'a123efghijklimnopqrstuvwxyz' (string_replace_pos)
POS: 1 0.000003815 DST: 'a123efghijklimnopqrstuvwxyz' (string_replace_fast)
POS: 1 0.000008583 DST: 'a123efghijklimnopqrstuvwxyz' (replace)
POS: 1 0.000012159 DST: 'a123efghijklimnopqrstuvwxyz' (replace2)

POS: 2 0.000007153 DST: 'ab123fghijklimnopqrstuvwxyz' (string_replace_pos)
POS: 2 0.000003815 DST: 'ab123fghijklimnopqrstuvwxyz' (string_replace_fast)
POS: 2 0.000010014 DST: 'ab123fghijklimnopqrstuvwxyz' (replace)
POS: 2 0.000012159 DST: 'ab123fghijklimnopqrstuvwxyz' (replace2)

POS: 3 0.000007391 DST: 'abc123ghijklimnopqrstuvwxyz' (string_replace_pos)
POS: 3 0.000003815 DST: 'abc123ghijklimnopqrstuvwxyz' (string_replace_fast)
POS: 3 0.000011206 DST: 'abc123ghijklimnopqrstuvwxyz' (replace)
POS: 3 0.000015497 DST: 'abc123ghijklimnopqrstuvwxyz' (replace2)

POS: 4 0.000007629 DST: 'abcd123hijklimnopqrstuvwxyz' (string_replace_pos)
POS: 4 0.000004053 DST: 'abcd123hijklimnopqrstuvwxyz' (string_replace_fast)
POS: 4 0.000013351 DST: 'abcd123hijklimnopqrstuvwxyz' (replace)
POS: 4 0.000012636 DST: 'abcd123hijklimnopqrstuvwxyz' (replace2)

POS: 5 0.000007629 DST: 'abcde123ijklimnopqrstuvwxyz' (string_replace_pos)
POS: 5 0.000004053 DST: 'abcde123ijklimnopqrstuvwxyz' (string_replace_fast)
POS: 5 0.000014544 DST: 'abcde123ijklimnopqrstuvwxyz' (replace)
POS: 5 0.000012636 DST: 'abcde123ijklimnopqrstuvwxyz' (replace2)

POS: 6 0.000007391 DST: 'abcdef123jklimnopqrstuvwxyz' (string_replace_pos)
POS: 6 0.000004053 DST: 'abcdef123jklimnopqrstuvwxyz' (string_replace_fast)
POS: 6 0.000015736 DST: 'abcdef123jklimnopqrstuvwxyz' (replace)
POS: 6 0.000012636 DST: 'abcdef123jklimnopqrstuvwxyz' (replace2)

POS: 7 0.000007629 DST: 'abcdefg123klimnopqrstuvwxyz' (string_replace_pos)
POS: 7 0.000004053 DST: 'abcdefg123klimnopqrstuvwxyz' (string_replace_fast)
POS: 7 0.000018358 DST: 'abcdefg123klimnopqrstuvwxyz' (replace)
POS: 7 0.000012636 DST: 'abcdefg123klimnopqrstuvwxyz' (replace2)

POS: 8 0.000007629 DST: 'abcdefgh123limnopqrstuvwxyz' (string_replace_pos)
POS: 8 0.000004053 DST: 'abcdefgh123limnopqrstuvwxyz' (string_replace_fast)
POS: 8 0.000019550 DST: 'abcdefgh123limnopqrstuvwxyz' (replace)
POS: 8 0.000012636 DST: 'abcdefgh123limnopqrstuvwxyz' (replace2)

POS: 9 0.000007629 DST: 'abcdefghi123imnopqrstuvwxyz' (string_replace_pos)
POS: 9 0.000003815 DST: 'abcdefghi123imnopqrstuvwxyz' (string_replace_fast)
POS: 9 0.000020504 DST: 'abcdefghi123imnopqrstuvwxyz' (replace)
POS: 9 0.000012636 DST: 'abcdefghi123imnopqrstuvwxyz' (replace2)

POS: 10 0.000007629 DST: 'abcdefghij123mnopqrstuvwxyz' (string_replace_pos)
POS: 10 0.000003815 DST: 'abcdefghij123mnopqrstuvwxyz' (string_replace_fast)
POS: 10 0.000032425 DST: 'abcdefghij123mnopqrstuvwxyz' (replace)
POS: 10 0.000012159 DST: 'abcdefghij123mnopqrstuvwxyz' (replace2)

POS: 11 0.000007391 DST: 'abcdefghijk123nopqrstuvwxyz' (string_replace_pos)
POS: 11 0.000003815 DST: 'abcdefghijk123nopqrstuvwxyz' (string_replace_fast)
POS: 11 0.000021696 DST: 'abcdefghijk123nopqrstuvwxyz' (replace)
POS: 11 0.000012159 DST: 'abcdefghijk123nopqrstuvwxyz' (replace2)

POS: 12 0.000007391 DST: 'abcdefghijkl123opqrstuvwxyz' (string_replace_pos)
POS: 12 0.000003815 DST: 'abcdefghijkl123opqrstuvwxyz' (string_replace_fast)
POS: 12 0.000022888 DST: 'abcdefghijkl123opqrstuvwxyz' (replace)
POS: 12 0.000012159 DST: 'abcdefghijkl123opqrstuvwxyz' (replace2)

POS: 13 0.000007391 DST: 'abcdefghijkli123pqrstuvwxyz' (string_replace_pos)
POS: 13 0.000003815 DST: 'abcdefghijkli123pqrstuvwxyz' (string_replace_fast)
POS: 13 0.000023842 DST: 'abcdefghijkli123pqrstuvwxyz' (replace)
POS: 13 0.000012159 DST: 'abcdefghijkli123pqrstuvwxyz' (replace2)

POS: 14 0.000007153 DST: 'abcdefghijklim123qrstuvwxyz' (string_replace_pos)
POS: 14 0.000003815 DST: 'abcdefghijklim123qrstuvwxyz' (string_replace_fast)
POS: 14 0.000024796 DST: 'abcdefghijklim123qrstuvwxyz' (replace)
POS: 14 0.000015736 DST: 'abcdefghijklim123qrstuvwxyz' (replace2)

POS: 15 0.000007391 DST: 'abcdefghijklimn123rstuvwxyz' (string_replace_pos)
POS: 15 0.000003815 DST: 'abcdefghijklimn123rstuvwxyz' (string_replace_fast)
POS: 15 0.000025749 DST: 'abcdefghijklimn123rstuvwxyz' (replace)
POS: 15 0.000015497 DST: 'abcdefghijklimn123rstuvwxyz' (replace2)

POS: 16 0.000007153 DST: 'abcdefghijklimno123stuvwxyz' (string_replace_pos)
POS: 16 0.000003815 DST: 'abcdefghijklimno123stuvwxyz' (string_replace_fast)
POS: 16 0.000026941 DST: 'abcdefghijklimno123stuvwxyz' (replace)
POS: 16 0.000015497 DST: 'abcdefghijklimno123stuvwxyz' (replace2)

POS: 17 0.000007153 DST: 'abcdefghijklimnop123tuvwxyz' (string_replace_pos)
POS: 17 0.000003815 DST: 'abcdefghijklimnop123tuvwxyz' (string_replace_fast)
POS: 17 0.000027895 DST: 'abcdefghijklimnop123tuvwxyz' (replace)
POS: 17 0.000015497 DST: 'abcdefghijklimnop123tuvwxyz' (replace2)

POS: 18 0.000007153 DST: 'abcdefghijklimnopq123uvwxyz' (string_replace_pos)
POS: 18 0.000004053 DST: 'abcdefghijklimnopq123uvwxyz' (string_replace_fast)
POS: 18 0.000028849 DST: 'abcdefghijklimnopq123uvwxyz' (replace)
POS: 18 0.000015497 DST: 'abcdefghijklimnopq123uvwxyz' (replace2)

POS: 19 0.000007153 DST: 'abcdefghijklimnopqr123vwxyz' (string_replace_pos)
POS: 19 0.000003815 DST: 'abcdefghijklimnopqr123vwxyz' (string_replace_fast)
POS: 19 0.000029802 DST: 'abcdefghijklimnopqr123vwxyz' (replace)
POS: 19 0.000015497 DST: 'abcdefghijklimnopqr123vwxyz' (replace2)

POS: 20 0.000007391 DST: 'abcdefghijklimnopqrs123wxyz' (string_replace_pos)
POS: 20 0.000003815 DST: 'abcdefghijklimnopqrs123wxyz' (string_replace_fast)
POS: 20 0.000030994 DST: 'abcdefghijklimnopqrs123wxyz' (replace)
POS: 20 0.000015497 DST: 'abcdefghijklimnopqrs123wxyz' (replace2)

POS: 21 0.000007153 DST: 'abcdefghijklimnopqrst123xyz' (string_replace_pos)
POS: 21 0.000003815 DST: 'abcdefghijklimnopqrst123xyz' (string_replace_fast)
POS: 21 0.000031948 DST: 'abcdefghijklimnopqrst123xyz' (replace)
POS: 21 0.000015497 DST: 'abcdefghijklimnopqrst123xyz' (replace2)

POS: 22 0.000007153 DST: 'abcdefghijklimnopqrstu123yz' (string_replace_pos)
POS: 22 0.000003815 DST: 'abcdefghijklimnopqrstu123yz' (string_replace_fast)
POS: 22 0.000032902 DST: 'abcdefghijklimnopqrstu123yz' (replace)
POS: 22 0.000015497 DST: 'abcdefghijklimnopqrstu123yz' (replace2)

POS: 23 0.000007391 DST: 'abcdefghijklimnopqrstuv123z' (string_replace_pos)
POS: 23 0.000003815 DST: 'abcdefghijklimnopqrstuv123z' (string_replace_fast)
POS: 23 0.000034094 DST: 'abcdefghijklimnopqrstuv123z' (replace)
POS: 23 0.000015497 DST: 'abcdefghijklimnopqrstuv123z' (replace2)

POS: 24 0.000007153 DST: 'abcdefghijklimnopqrstuvw123' (string_replace_pos)
POS: 24 0.000003815 DST: 'abcdefghijklimnopqrstuvw123' (string_replace_fast)
POS: 24 0.000034571 DST: 'abcdefghijklimnopqrstuvw123' (replace)
POS: 24 0.000015497 DST: 'abcdefghijklimnopqrstuvw123' (replace2)

POS: 25 0.000007153 DST: 'abcdefghijklimnopqrstuvwx123' (string_replace_pos)
ERROR: length mismatch -- EXPECTED: 27 ACTUAL: 28
POS: 25 0.000003815 DST: 'abcdefghijklimnopqrstuvwx123' (string_replace_fast)
ERROR: length mismatch -- EXPECTED: 27 ACTUAL: 28
POS: 25 0.000034571 DST: 'abcdefghijklimnopqrstuvwx12' (replace)
POS: 25 0.000014305 DST: 'abcdefghijklimnopqrstuvwx12' (replace2)

POS: 26 0.000007153 DST: 'abcdefghijklimnopqrstuvwxy123' (string_replace_pos)
ERROR: length mismatch -- EXPECTED: 27 ACTUAL: 29
POS: 26 0.000003815 DST: 'abcdefghijklimnopqrstuvwxy123' (string_replace_fast)
ERROR: length mismatch -- EXPECTED: 27 ACTUAL: 29
POS: 26 0.000034809 DST: 'abcdefghijklimnopqrstuvwxy1' (replace)
POS: 26 0.000012636 DST: 'abcdefghijklimnopqrstuvwxy1' (replace2)

POS: 27 0.000007391 DST: 'abcdefghijklimnopqrstuvwxyz123' (string_replace_pos)
ERROR: length mismatch -- EXPECTED: 27 ACTUAL: 30
POS: 27 0.000003815 DST: 'abcdefghijklimnopqrstuvwxyz123' (string_replace_fast)
ERROR: length mismatch -- EXPECTED: 27 ACTUAL: 30
POS: 27 0.000148058 DST: 'abcdefghijklimnopqrstuvwxyz' (replace)
POS: 27 0.000008821 DST: 'abcdefghijklimnopqrstuvwxyz' (replace2)

POS: 28 0.000007629 DST: 'abcdefghijklimnopqrstuvwxyz' (string_replace_pos)
POS: 28 0.000003815 DST: 'abcdefghijklimnopqrstuvwxyz' (string_replace_fast)
POS: 28 0.000039339 DST: 'abcdefghijklimnopqrstuvwxyz' (replace)
POS: 28 0.000012159 DST: '123defghijklimnopqrstuvwxyz' (replace2)

POS: 29 0.000007391 DST: 'abcdefghijklimnopqrstuvwxyz' (string_replace_pos)
POS: 29 0.000003815 DST: 'abcdefghijklimnopqrstuvwxyz' (string_replace_fast)
POS: 29 0.000035048 DST: 'abcdefghijklimnopqrstuvwxyz' (replace)
POS: 29 0.000011921 DST: '123defghijklimnopqrstuvwxyz' (replace2)

POS: 30 0.000007153 DST: 'abcdefghijklimnopqrstuvwxyz' (string_replace_pos)
POS: 30 0.000003815 DST: 'abcdefghijklimnopqrstuvwxyz' (string_replace_fast)
POS: 30 0.000035048 DST: 'abcdefghijklimnopqrstuvwxyz' (replace)
POS: 30 0.000012159 DST: '123defghijklimnopqrstuvwxyz' (replace2)
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • Interesting implementation, this is what I did, the same thing but without any safety. I'm writing this code for a microcontroller, would the safety check affect performance? Also I think with this current code I am overwriting memory that doesn't belong to the dest string if the source string length plus the pos argument are greater than strlen(dest). ```void string_replace_pos(char dest[], char source[], char pos) { int source_length = strlen(source); for(int i = 0; i < source_length; i++) { dest[pos + i] = source[i]; } } ``` – Rs Fps Jan 28 '19 at 22:33
  • Dear Mr.Estey, I get previously your a lot of helps sir. Nowadays I need and I will need your helps as well. If you can glance at the problem on my simple program, I really appreciate you. I do its explanation as comment at the beginning of the file. My problem is merely "using" pipes as I explain in the comment. I am looking forward to hearing from you. The C file is http://snrkr.com/soner_aid.c Best Regards. – Soner from The Ottoman Empire Mar 25 '19 at 16:00
0

Since a string is a pointer to its first character, if you know which index you want to write to, you can just do this:

void string_insert_and_replace(char *dest, char *src, size_t pos)
{
    while (*src)
    {
        *(dest + pos) = *src;
        dest++, src++;
    }
}

Assuming sufficient space in dest to hold the entirety of pos + strlen(src) + 1 (I think).

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
  • I thought of something similar. Adding on to another answer on here, just modified to use while loops. The extra checks prevent writing to the dest string when it runs out of space. ``` void string_replace_pos(char dest[], char source[], char pos) { while((*dest != '\0') && (pos > 0)) { dest++; pos--; } while((*dest != '\0') && (*source != '\0')) { *dest = *source; dest++; source++; } } ``` – Rs Fps Jan 28 '19 at 23:00
0

If one wants performance with long strings, consider memcpy, which is probably optimised to the architecture.

#include <string.h> /* memcpy strlen */
#include <stdio.h>  /* printf */
#include <assert.h>

static void string_insert_and_replace(char *str_dest,
    const char *str_source, const size_t offset) {
    const size_t len_dest = strlen(str_dest), len_source = strlen(str_source);
    size_t n = len_source;
    assert(str_dest && str_source);
    if(offset + len_source > len_dest) {
        if(offset >= len_dest) return;
        n = len_dest - offset;
    }
    memcpy(str_dest + offset, str_source, n);
}

int main(void) {
    char str_dest[] = "abcdefg";
    char str_source[] = "123";

    /* The 3rd argument is the position to insert at */
    string_insert_and_replace(str_dest, str_source, 5);

    /* str_dest should now be "abc123g" */
    printf("%s\n", str_dest);

    return 0;
}

Edit: In the former, if the source goes past the dest+offset, then strlen counts past the end of the copyable length for nothing. The following is modified to truncate the search.

#include <string.h> /* memchr memcpy strlen */
#include <stdio.h>  /* printf */
#include <assert.h>

static void string_insert_and_replace(char *str_dest,
    const char *str_source, const size_t offset) {
    const size_t len_dest = strlen(str_dest);
    size_t n;
    char *null_source;
    assert(str_dest && str_source);
    /* This is the maximum bytes it could copy without overflow. */
    if(offset >= len_dest) return;
    n = len_dest - offset;
    /* If source is shorter then the remaining dest. */
    if((null_source = memchr(str_source, '\0', n)))
        n = (size_t)(null_source - str_source);
    memcpy(str_dest + offset, str_source, n);
}
Neil
  • 1,767
  • 2
  • 16
  • 22
-1

Whenever you abstract any string functions, you should ALWAYS minimally supply the available size of any destination buffer, and, if possible, the max size of the source buffer to avoid issues with strings missing null terminators.

Which means something like

void string_insert_and_replace(char *dest, int dlen, const char *src, int slen, int off)
{
    ...
}

If you find yourself using strcpy and/or strlen instead of strncpy and strnlen you are doing it wrong. Ignore anyone's code that even suggests doing so.

nyet
  • 482
  • 2
  • 13
  • 1
    Interesting comment about the `strn*` family of functions. You may find the discussion on [this question](https://stackoverflow.com/questions/869883/why-is-strncpy-insecure) interesting. – Govind Parmar Jan 28 '19 at 22:21
  • Indeed. In fact, I generally use xsnprintf() or snprintf() instead of strncpy() for exactly the reasons mentioned in that thread. – nyet Jan 30 '19 at 05:32