Удалить первый и последний символ из строки - PullRequest
2 голосов
/ 31 января 2020

Задача должна быть простой, удалить первый и последний символы.

https://www.codewars.com/kata/56bc28ad5bdaeb48760009b0/train/c

Функция получает два параметра (dst в качестве пункта назначения и src в качестве источника) и должна вернуть измененную строку и присвоить * Указатель 1010 * (если я правильно понял).

Мой ответ мне кажется правильным, но вот моя проблема:

Когда строка содержит более 9 символов, измененная строка поставляется с некоторыми символы.

char* remove_char(char* dst, const char* src){

  memmove(dst,src+1,strlen(src+1)-1);


  return dst;
}

Заранее благодарим за помощь:)

Ответы [ 3 ]

6 голосов
/ 31 января 2020

При этом:

memmove(dst,src+1,strlen(src+1)-1);

Вы правильно пропускаете первый и последний символ, но в итоге получаете строку, которая не имеет терминатора NUL (\0). Вы должны добавить его самостоятельно до или после memmove:

size_t len = strlen(src) - 2;
memmove(dst, src + 1, len);
dst[len] = '\0';

Конечно, весь приведенный выше код предполагает, что dst был правильно выделен и может содержать не менее strlen(src) - 1 символов и что src содержит не менее 2 символов.

Если вы также хотите учесть крайний случай, в котором src короче двух символов:

size_t len = strlen(src);

if (len < 2) {
    *dst = '\0';
} else {
    memmove(dst, src + 1, len - 2);
    dst[len - 2] = '\0';
}

return dst;

Примечание: вы возможно, придется #include <stddef.h> использовать size_t.

3 голосов
/ 31 января 2020

Этот вызов

memmove(dst,src+1,strlen(src+1)-1);

не создает строку в массиве символов, на которую указывает указатель dst, поскольку конечный ноль не копируется и целевой массив не может быть инициализирован нулями.

Также выражение strlen( src + 1 ) - 1 может вызывать неопределенное поведение.

И нет смысла использовать memmove при условии, что символьные массивы не перекрываются.

Вот демонстрационная программа, которая показывает как задача может быть выполнена.

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

char * remove_char( char * restrict dst, const char * restrict src )
{
    size_t n = strlen( src );

    n = n < 2 ? 0 : n - 2;

    if ( n != 0 )
    {
        memcpy( dst, src + 1, n );
    }

    dst[n] = '\0';

    return dst;
}

int main(void) 
{
    enum { N = 10 };
    char dst[N];

    printf( "\"%s\"\n", remove_char( dst, "" ) );
    printf( "\"%s\"\n", remove_char( dst, "1" ) );
    printf( "\"%s\"\n", remove_char( dst, "12" ) );
    printf( "\"%s\"\n", remove_char( dst, "121" ) );

    return 0;
}

Вывод программы:

""
""
""
"2"
0 голосов
/ 02 февраля 2020

Ваш код имеет несколько проблем:

  • он не работает, потому что вы не устанавливаете нулевой терминатор в конце массива назначения.
  • он хрупок, потому что вы не тестируете длина исходной строки должна быть не менее 2 байтов, что приводит к неопределенному поведению для более коротких строк.
  • она компилируется случайно, потому что вы не включаете <string.h> и, таким образом, вызываете функции без надлежащего прототипа. Прототипы, выведенные компилятором, неверны.

Solution , размещенное в онлайн-компиляторе codewars, должно компилироваться как отдельный файл. Он должен включать соответствующие файлы, такие как <string.h>, если вы используете memmove() или strlen().

Вот исправленное решение:

#include <string.h>

char *remove_char(char *dst, const char *src) {
    size_t len = strlen(src);
    if (len >= 2) {
        memmove(dst, src + 1, len - 2);
        dst[len - 2] = '\0';
    } else {
        *dst = '\0';
    }
    return dst;
}
...