C вставьте и замените строку в позиции - PullRequest
0 голосов
/ 28 января 2019

Как вставить строку (источник) в другую строку (dest) в C в определенной позиции, перезаписав строку назначения (вместо смещения содержимого строки назначения в позицию вставки).

Функция, такая как 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 ]

0 голосов
/ 29 января 2019

Если вам нужна производительность с длинными строками, рассмотрите 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);
}
0 голосов
/ 28 января 2019

Всякий раз, когда вы абстрагируете какие-либо строковые функции, вы ВСЕГДА должны минимально указывать доступный размер любого целевого буфера и, если возможно, максимальный размер исходного буфера, чтобы избежать проблем со строками, в которых отсутствуют нулевые терминаторы.

Что означает что-то вроде

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

Если вы обнаружите, что используете strcpy и / или strlen вместо strncpy и strnlen, вы делаете это неправильно.Игнорируйте чей-либо код, который даже предлагает сделать это.

0 голосов
/ 29 января 2019

Поскольку строка является указателем на свой первый символ, если вы знаете, какой индекс вы хотите записать, вы можете просто сделать это:

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

Предполагая, что в dest достаточно места для храненияв целом pos + strlen(src) + 1 (я думаю).

0 голосов
/ 28 января 2019

Вот версия, которая работает.Я включил также несколько модульных тестов:

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

ОБНОВЛЕНИЕ:

Я пишу этот код для микроконтроллера, будетпроверка безопасности влияет на производительность?

Да, проверка безопасности требует, чтобы строка destination сканировалась побайтно, чтобы найти конец.

Обратите внимание, что нет необходимо сделать strlen для строки source .См. string_replace_fast вариант вашей функции ниже.Это не намного безопаснее, но это на [приблизительно в 2 раза] быстрее.

Также я думаю, что с этим текущим кодом я перезаписываю память, которая не принадлежит месту назначениястрока, если длина исходной строки плюс аргумент pos больше, чем strlen (dest).

Да, это правильно.Вы можете увидеть это в результатах теста ниже.

Возможно, вам придется пожертвовать немного скоростью.Если это не функция, которая называется lot , тогда выберите более медленную / безопасную версию.Вы можете сказать это только с помощью некоторого бенчмаркинга.

Вот модифицированная версия тестовой программы, которая имеет бенчмаркинг для вашей и моей версии вместе с одним или двумя вариантами:

#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)
...