Создайте C-программу для копирования элементов массива char из одного массива в другой, и вам не нужно беспокоиться о нулевом символе - PullRequest
0 голосов
/ 07 октября 2018

Я хочу создать программу, которая копирует, элемент за элементом, один массив символов в другой, но проблема в том, что, если я не введу в массив назначения нулевой символ, программа выведет правильные символы String + странные символыТаким образом, мое решение состояло в том, чтобы выполнить итерацию по длине строки + 1, чтобы включить нулевой символ, есть ли способ выполнить итерацию по длине строки, не беспокоясь о нулевом символе?Код выглядит следующим образом:

int copy(char * source, char * destination, unsigned int lengthDestination);

int copy(char * source, char * destination, unsigned int lengthDestination) 
{
    int i;
    for(i = 0; source[i] != '\0'; i++) {
        //Count the length of the source array
    }
    if(i + 1 != lengthDestination){ //i + 1 in order to take into account '\0'
       return 1;
    }

    for(int j = 0; j < lengthDestination; j++) {
        destination[j] = source[j];
    }
    return 0;
}

int main() {
    char * source = "Test number 17"; //Length is 15 counting the null character
    unsigned int destinationLength = 15;
    char destination[destinationLength];
    copy(source, destination, destinationLength);
    printf("The String source is: %s\n", source);
    printf("The String destination is: %s\n", destination);
    return 0;
}

Ответы [ 3 ]

0 голосов
/ 07 октября 2018

Самый простой способ:

char *copy(const char *source, char *destination, size_t lengthDestination)
{
    memcpy(destination, source, lengthDestination -1);
    destination[lengthDestination -1] = 0;
    return destination;
}
0 голосов
/ 08 октября 2018

Если вы передаете destination, ранее объявленный с автоматическим типом хранения или как указатель, ранее выделенный с malloc, calloc или realloc с выделенным типом хранения, и в любом случае сnchars свободного места, вы можете реализовать довольно надежную функцию copy, просто используя snprintf.

Поскольку вы передаете максимальное количество символов, включая nul-terminating символ в качестве параметра вашей copy функции, которая прекрасно согласуется с параметром size для snprintf.Кроме того, snprintf обеспечит строку с нулевым символом в конце в месте назначения - даже если source слишком длинный, чтобы поместиться в destination.В качестве преимущества, snprintf возвращает количество скопированных символов, если в destination достаточно места для source, в противном случае возвращается количество символов , которое было бы скопировано было бы destinationдостаточно места - позволяет вам определить количество усеченных символов, если destination недостаточно для удержания вашей строки source.

Перед рассмотрением реализации copy давайте рассмотрим прототип и поговорим ообъявляя функции тем, что они обеспечивают значимый возврат, и пока вы сами, давайте также рассмотрим порядок параметров и спецификатора типа для source, например,

/* simple strcpy src to dest, returns dest on success and number of chars
 * (including nul-termining char) in nchar, returns NULL otherwise.
 */
char *copy (char *dest, const char *src, size_t *nchar);

Если вы заметили, большинство строковых функций возвращаютуказатель на строку назначения в случае успеха (или NULL в противном случае), который позволяет немедленно использовать возврат.Далее, хотя это и не ограничитель показа, большинство строковых (или вообще памяти) функций копирования помещают destination в качестве первого параметра, за которым следует source.Я уверен, что либо Брайан Керриган, либо Деннис Ритчи могли бы объяснить почему, но достаточно сказать, что большинство параметров функции копирования упорядочены таким образом.

Обратите внимание, что, поскольку вы не изменяете строку source в copy, лучше всего квалифицировать параметр как const.Квалификатор const - это более или менее обещание, которое вы даете компилятору, что source не будет изменено в copy, что позволяет компилятору предупреждать, если он видит, что вы нарушаете это обещание, а также позволяет компилятору дополнительно оптимизироватьфункция, знающая, что source не изменится.

Наконец, обратите внимание, что ваш size или мой nchar передается как указатель выше вместо непосредственного значения.Поскольку функция в C может возвращать только одно значение, если вам нужен способ вернуть второй фрагмент информации вызывающей стороне, передайте указатель в качестве параметра, чтобы значение по этому адресу можно было обновить в функции, создавая новыйзначение, доступное для вызывающей функции.Здесь вы возвращаете указатель на dest (или NULL), указывающий на успех / неудачу, а также обновляет nchar, чтобы он содержал количество символов в dest (включая символ с нулевым окончанием какВы указали размер , а не длина ).

Определение copy довольно короткое и упрощенное.Единственное требование - строки source и destination не должны перекрываться.(в этом случае не определены ни strcpy, ни snprintf).Основной поток состоит в том, чтобы проверить , оба src и dest не NULL, а затем обработать случай, когда src - это "empty-string" (например, 1-й символ - nul-), а затем скопировать src в dest, используя snprintf, сохранив возврат в written, а затем используя простое условное выражение, чтобы определить, произошло ли усечение (и предупреждение в этом случае), и в заключение обновивзначение, на которое указывает nchar и возвращающее dest, например,

/* simple strcpy src to dest, returns dest on success and number of chars
 * (including nul-termining char) in nchar, returns NULL otherwise.
 */
char *copy (char *dest, const char *src, size_t *nchar)
{
    if (!src || !dest) {    /* validate src & dest not NULL */
        fputs ("error: src or dest NULL\n", stderr);
        return NULL;        /* return NULL on error */
    }

    if (!*src)  /* handle src being an "empty-string" */
        *dest = 0, *nchar = 0;

    int written = snprintf (dest, *nchar, "%s", src);   /* call snprintf */

    if ((size_t)written + 1 > *nchar) { /* handle truncated case */
        fprintf (stderr, "warning: dest truncated by %zu chars.\n",
                (size_t)(written + 1) - *nchar);    /* warn with count */
    }
    else     /* src fit in dest, set nchar to no. of chars in dest */
        *nchar = (size_t)(written + 1); /* including nul-character */

    return dest;     /* return dest so available for immediate use */
}

В целом его можно привести в коротком примере, в котором для копирования в качестве первого аргумента программы используется строка (по умолчанию используется "source string")если аргумент не указан), вы можете сделать что-то вроде следующего:

#include <stdio.h>

#define MAXC 16     /* constant for destination length */

/* simple strcpy src to dest, returns dest on success and number of chars
 * (including nul-termining char) in nchar, returns NULL otherwise.
 */
char *copy (char *dest, const char *src, size_t *nchar)
{
    if (!src || !dest) {    /* validate src & dest not NULL */
        fputs ("error: src or dest NULL\n", stderr);
        return NULL;        /* return NULL on error */
    }

    if (!*src)  /* handle src being an "empty-string" */
        *dest = 0, *nchar = 0;

    int written = snprintf (dest, *nchar, "%s", src);   /* call snprintf */

    if ((size_t)written + 1 > *nchar) { /* handle truncated case */
        fprintf (stderr, "warning: dest truncated by %zu chars.\n",
                (size_t)(written + 1) - *nchar);    /* warn with count */
    }
    else     /* src fit in dest, set nchar to no. of chars in dest */
        *nchar = (size_t)(written + 1); /* including nul-character */

    return dest;     /* return dest so available for immediate use */
}

int main (int argc, char **argv) {

    char *src = argc > 1 ? argv[1] : "source string",
        dest[MAXC];
    size_t n = MAXC;

    if (copy (dest, src, &n))
        printf ("dest: '%s' (%zu chars including nul-char)\n", dest, n);
}

( note: максимальное количество символов в dest намеренно сокращено, чтобы легко показать, какобрабатывается усечение - размер соответствует вашим потребностям)

Пример использования / Вывод

$ ./bin/strcpy_snprintf
dest: 'source string' (14 chars including nul-char)

Отображение максимального количества символов, которое можно скопировать без предупреждения:

$ ./bin/strcpy_snprintf  123456789012345
dest: '123456789012345' (16 chars including nul-char)

Отображение источника обработки, слишком длинного для места назначения:

$ ./bin/strcpy_snprintf  1234567890123456
warning: dest truncated by 1 chars.
dest: '123456789012345' (16 chars including nul-char)

Просмотрите все и дайте мне знать, если выесть дополнительные вопросы.Существует как минимум дюжина различных способов приблизиться к копированию строки, но, учитывая, что вы передаете dest со своим собственным хранилищем и передаете максимальное количество символов (включая nul-символ ) в качестве параметра,в этом случае трудно победить snprintf.

0 голосов
/ 07 октября 2018

Вам всегда нужно будет «беспокоиться» о нулевом терминаторе, в том смысле, что вы не можете не иметь нулевой терминатор в вашей целевой C-строке, и вам всегда нужно будет явно написатьнулевой терминатор в конце вашей новой строки C.

Даже встроенный метод strcpy скопирует нулевой символ-терминатор из исходной строки в строку назначения.

#include <stdio.h>
#include <assert.h>

int copy(char * source, char * destination, unsigned int lengthDestination);

int copy(char * source, char * destination, unsigned int lengthDestination)
{
    int i;
    for(i = 0; source[i] != '\0'; i++) {
        destination[i] = source[i];
    }
    assert(i+1 == lengthDestination);
    destination[i+1] = '\0';
    return 0;
}

int main() {
    char * source = "Test number 17"; //Length is 15 counting the null character
    unsigned int destinationLength = 15;
    char destination[destinationLength];
    copy(source, destination, destinationLength);
    printf("The String source is: %s\n", source);
    printf("The String destination is: %s\n", destination);
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...