2017-01-26 8 views
1

Функция strncpy() не всегда заканчивается так, что я хочу знать, что является лучшей альтернативой, которая всегда нулевая. Я хочу функцию, если:Что является лучшей альтернативой strncpy()?

strlen(src) >= n /*n is the number of characters to be copied from source*/ 

нет никакой необходимости добавлять дальнейший код:

buf[sizeof(buf)-1] = 0; 
+3

Посмотрите на [ 'strncpy_s'] (http://en.cppreference.com/w/c/string/byte/strncpy) –

+0

Посмотрите на [ссылка] (HTTP: // WWW. cplusplus.com/reference/cstring/strncpy/). Вы можете использовать strcpy() или добавить символ самостоятельно, если знаете значение n. destination [n] = '\ 0' – Carles

+0

@Carles Yea Я знаю, но я хочу знать функцию, которая автоматически добавляет нулевой символ в конце строки –

ответ

6

Если длина строки, которую вы желаете скопировать неизвестно, вы можете использовать snprintf здесь. Эта функция отправляет отформатированный результат на str. Он действует аналогично sprintf(), но вместо этого не записывает больше байтов, выделенных str. Если результирующая строка длиннее n-1 символов, то оставшиеся символы не учитываются. Он также всегда включает нулевой ограничитель \0, если размер буфера не равен 0.

Это была бы альтернатива strncpy() или strcpy(), если вы действительно не хотите ее использовать. Однако вручную добавление нулевого терминатора в конце строки с strcpy() - это простой и эффективный подход. В C очень нормально добавлять нулевой ограничитель в конце любой обработанной строки.

Вот основной пример использования sprintf():

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

#define SIZE 1024 

int main(void) { 
    const size_t N = SIZE; 
    char str[N]; 
    const char *example = "Hello World"; 

    snprintf(str, sizeof(str), "%s", example); 

    printf("String = %s, Length = %zu\n", str, strlen(str)); 

    return 0; 
} 

, которая печатает:

String = Hello World, Length = 11 

Этот пример показывает, что snprintf() копируются "Hello World" в str, а также добавили \0 терминатор на конец.

Примечание:strlen() работает только нулем строки, и будет вызывать undefined behaviour, если строка не нулем. snprintf() также нуждается в дополнительной проверке ошибок, которую можно найти на man page.

Как говорили другие, это не эффективный подход, но он есть, если вы смотрите.

+0

Небольшой пример будет хорошим. Мы не хотим, чтобы новички делали что-то ужасное, как 'snprintf (dst, DST_SIZE, src);' – user694733

+1

snprintf ужасно неэффективен. Если вы хотите использовать его только для копирования строк, вы тратите ресурсы. – Lundin

+0

@ user694733 добавил базовый пример, я все еще не уверен, почему OP не хочет использовать 'strcpy()' хотя. – RoadRunner

1

Используйте strlcpy() функцию. strlcpy() берут полный размер буфера назначения и гарантируют NULL-окончание, если есть место. Для получения дополнительной информации прочитайте страницу man.

+2

Я не думаю, что' strlcpy' является стандартным, и я для одного предпочитают стандартные функции здесь. – Downvoter

+0

Существует функция 'strcpy_s', стандартная как C11, но компиляторы не должны ее поддерживать. Тем не менее он более стандартный, чем 'strlcpy'. И нет никакой реальной причины использовать любой из них ... – Lundin

-1

Функция strcpy всегда имеет значение null-terminates. Конечно, вы должны включать в себя код, чтобы предотвратить переполнение буфера и т.д .:

char buf[50]; 

if (strlen(src) >= sizeof buf) 
{ 
    // do something else... 
} 
else 
    strcpy(buf, src); 
3

В качестве альтернативы answer, который предложил snprintf(): (Примечание: если неприятности n <= 0)

size_t sz = sizeof buf; 
/*n is the number of characters to be copied from source*/ 
int n = (int) sz - 1; 
snprintf(buf, sz, "%s", src); 

код можно использовать следующую точность:

»... максимальное количество байтов для преобразования s. ... "C11 §7.21.6.1 4

sprintf(buf, "%.*s", n, src); 

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

Другой инструмент для струн.

+0

Зачем передавать 'n - 1' на' snprintf() '? усечение произойдет один байт слишком рано. И наоборот, вы должны передать 'n - 1' для формата'%. * S', если 'n' - размер целевого буфера, и вы должны сделать его следующим образом:' sprintf (buf, "%. * S", (int) (n - 1), src); 'если его тип' size_t'. – chqrlie

+0

@chqrlie Ответ переработан. Из OP "* n - количество символов, которые нужно скопировать из источника". а не размер буфера. – chux

2

Если поведение вы хотите версия -срезающая из strcpy, который копирует длинный начальный префикс из исходной строки в буфер известного размера, есть несколько вариантов для вас:

  • Вы можете написать индивидуальные функции, которая делает работу:

    char *safe_strcpy(char *dest, size_t size, char *src) { 
        if (size > 0) { 
         size_t i; 
         for (i = 0; i < size - 1 && src[i]; i++) { 
          dest[i] = src[i]; 
         } 
         dest[i] = '\0'; 
        } 
        return dest; 
    } 
    

    Большинство систем BSD имеют функцию strlcpy(char *dest, const char *src, size_t n);, которая работает так же. Порядок его аргументов запутан, так как n является размером массива dest, но приходит после аргумента src.

  • Вы можете использовать strncat():

    char *safe_strcpy(char *dest, size_t size, char *src) { 
        if (size > 0) { 
         *dest = '\0'; 
         strncat(dest, src, n - 1); 
        } 
        return dest; 
    } 
    
  • Вы можете использовать snprintf() или sprintf(), но он чувствует, как с помощью гидравлического пресса пробивать гвоздем:

    snprintf(dest, size, "%s", src); 
    

    Поочередно:

    if (size > 0) { 
        sprintf(dest, "%.*s", (int)(size - 1), src); 
    } 
    
  • Вы можете использовать strlen() и memcpy(), но это возможно только в том случае, если вы знаете, что исходный ptr указывает на строку с нулевым завершением. Кроме того, менее эффективен, чем оба вышеуказанных решений, если исходная строка гораздо длиннее, чем массив назначения:

    char *safe_strcpy(char *dest, size_t size, char *src) { 
        if (size > 0) { 
         size_t len = strlen(src); 
         if (len >= size) 
          len = size - 1; 
         memcpy(dest, src, len); 
         dest[len] = '\0'; 
        } 
        return dest; 
    } 
    
  • Вы можете использовать strncpy() и заставить нулевое окончание. Это было бы неэффективно, если массив назначения был большим, потому что strncpy() также заполняет остальную часть целевого массива нулевыми байтами, если исходная строка короче. семантика этой функции очень противоречит интуиции, плохо понимается и подвержена ошибкам. Даже при правильном использовании вхождения strncpy() являются ошибками, ожидающими своего появления, поскольку следующий программист, смелый, но менее сообразительный, может изменить код и ввести их в попытку оптимизировать код, который он не понимает. Играйте в безопасности: избегайте этой функции.

 Смежные вопросы

  • Нет связанных вопросов^_^