1

如何在 C 中的特定位置将一个字符串(源)插入另一个字符串(dest),覆盖目标字符串(而不是在插入位置移动目标字符串的内容)。

一个如下string_insert_and_replace抽象的函数;

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"
4

4 回答 4

0

这是一个有效的版本。我还包括了一些单元测试:

#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;
}

更新:

我正在为微控制器编写此代码,安全检查会影响性能吗?

是的,安全检查要求逐字节扫描目标字符串以定位结尾。

请注意,无需strlen字符串执行任何操作。请参阅string_replace_fast下面的功能变体。它并不安全,但速度快 [大约 2 倍]。

另外我认为,如果源字符串长度加上 pos 参数大于 strlen(dest),则使用当前代码我将覆盖不属于 dest 字符串的内存。

对,那是正确的。您可以在下面的测试结果中看到它。

您可能不得不牺牲一点速度。如果这不是一个被大量调用的函数,那么选择更慢/更安全的版本。您只能通过一些基准测试来判断这一点。

这是测试程序的修改版本,它对您的版本和我的版本进行了基准测试,以及一两个变体:

#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;
}

这是这个测试程序的输出。

请注意您的版本的错误行。另外,请注意如果插入位置为负数会发生什么。

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)
于 2019-01-28T01:17:02.100 回答
0

如果想要长字符串的性能,请考虑memcpy,这可能已针对架构进行了优化。

#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;
}

编辑:在前者中,如果source超过dest+offset,则strlen计算超过可复制长度的末尾。修改以下内容以截断搜索。

#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);
}
于 2019-01-29T02:00:16.813 回答
0

由于字符串是指向其第一个字符的指针,因此如果您知道要写入哪个索引,则可以这样做:

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

假设有足够的空间dest来容纳整个pos + strlen(src) + 1(我认为)。

于 2019-01-28T22:16:14.687 回答
-1

每当您抽象任何字符串函数时,您应该始终提供任何目标缓冲区的可用大小,并且如果可能的话,提供源缓冲区的最大大小以避免字符串缺少空终止符的问题。

这意味着类似

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

如果您发现自己使用strcpy和/或strlen代替strncpy并且strnlen您做错了。忽略任何甚至建议这样做的代码。

于 2019-01-28T01:23:14.767 回答