Почему вы должны использовать strncpy вместо strcpy?
Изменить: я добавил источник для примера.
Я наткнулся на этот пример:
char source[MAX] = "123456789";
char source1[MAX] = "123456789";
char destination[MAX] = "abcdefg";
char destination1[MAX] = "abcdefg";
char *return_string;
int index = 5;
/* This is how strcpy works */
printf("destination is originally = '%s'\n", destination);
return_string = strcpy(destination, source);
printf("after strcpy, dest becomes '%s'\n\n", destination);
/* This is how strncpy works */
printf( "destination1 is originally = '%s'\n", destination1 );
return_string = strncpy( destination1, source1, index );
printf( "After strncpy, destination1 becomes '%s'\n", destination1 );
Который произвел этот вывод:
пункт назначения изначально = 'abcdefg' После команды strcpy пункт назначения становится "123456789". destination1 изначально = 'abcdefg' После strncpy destination1 становится '12345fg'
Что заставляет меня задуматься, почему кому-то нужен такой эффект. Похоже, это будет сбивать с толку. Эта программа заставляет меня думать, что вы можете скопировать чье-то имя (например, Том Броко) с Томом Бро763.
Каковы преимущества использования strncpy()
над strcpy()
?
11 ответов
strncpy
борется с переполнением буфера, требуя, чтобы вы указали длину в нем. strcpy
зависит от трейлинга \0
, что может не всегда происходить.
Во-вторых, почему вы решили скопировать только 5 символов в строку из 7 символов, я не знаю, но это приводит к ожидаемому поведению. Это только копирование первого n
персонажи, где n
это третий аргумент.
n
все функции используются как защитное кодирование от переполнения буфера. Пожалуйста, используйте их вместо старых функций, таких как strcpy
,
strncpy()
Функция была разработана с учетом особой проблемы: манипулирование строками, хранящимися в виде оригинальных записей каталога UNIX. Они использовали массив фиксированного размера, и nul-terminator использовался только в том случае, если имя файла было короче массива.
Вот что стоит за двумя странностями strncpy()
:
- Он не помещает нуль-терминатор в пункт назначения, если он полностью заполнен; а также
- Он всегда полностью заполняет пункт назначения, с нулями, если это необходимо.
Для "безопаснее strcpy()
"Вам лучше использовать strncat()
вот так:
if (dest_size > 0)
{
dest[0] = '\0';
strncat(dest, source, dest_size - 1);
}
Это всегда обнуляет результат и не копирует больше, чем необходимо.
Пока я знаю намерение strncpy
Это не очень хорошая функция. Избегайте обоих. Раймонд Чен объясняет
Лично мой вывод просто избегать
strncpy
и все его друзья, если вы имеете дело со строкой, заканчивающейся нулем. Несмотря на "str" в названии, эти функции не создают строки с нулевым символом в конце. Они преобразуют строку с нулевым символом в конце в необработанный символьный буфер. Использовать их там, где ожидается строка с нулевым символом в конце, поскольку второй буфер явно неверен. Вы не только не можете получить правильное нулевое завершение, если источник слишком длинный, но и если источник короткий, вы получаете ненужное заполнение нулями.
Смотрите также Почему strncpy небезопасен?
strncpy НЕ безопаснее, чем strcpy, он просто торгует ошибками одного типа с другим. В C, при обработке строк C, вам нужно знать размер ваших буферов, нет никакого способа обойти это. strncpy был оправдан для каталога, упомянутого другими, но в противном случае вы никогда не должны использовать его:
- Если вы знаете длину вашей строки и буфера, зачем использовать strncpy? В лучшем случае это пустая трата вычислительной мощности (добавление бесполезных 0)
- если вы не знаете длины, то вы рискуете молча обрезать ваши строки, что не намного лучше, чем переполнение буфера
То, что вы ищете, это функция strlcpy()
который всегда завершает строку с 0 и инициализирует буфер. Он также способен обнаруживать переполнения. Единственная проблема, он не является (действительно) переносимым и присутствует только в некоторых системах (BSD, Solaris). Проблема с этой функцией в том, что она открывает еще одну банку с червями, что можно увидеть в обсуждениях на http://en.wikipedia.org/wiki/Strlcpy
Мое личное мнение таково, что это гораздо полезнее, чем strncpy()
а также strcpy()
, Он имеет лучшую производительность и является хорошим компаньоном для snprintf()
, Для платформ, которые не имеют его, это относительно легко реализовать.
(для фазы разработки приложения я заменяю эти две функции (snprintf()
а также strlcpy()
) с перехватом версии, которая жестоко прерывает программу при переполнении буфера или усечении. Это позволяет быстро поймать худших преступников. Особенно, если вы работаете над базой кода от кого-то еще.
РЕДАКТИРОВАТЬ: strlcpy()
может быть легко реализовано:
size_t strlcpy(char *dst, const char *src, size_t dstsize)
{
size_t len = strlen(src);
if(dstsize) {
size_t bl = (len < dstsize-1 ? len : dstsize-1);
((char*)memcpy(dst, src, bl))[bl] = 0;
}
return len;
}
strncpy()
функция безопаснее: вам нужно передать максимальную длину, которую может принять целевой буфер. В противном случае может случиться, что исходная строка не будет корректно завершена на 0, и в этом случае strcpy()
Функция может записывать больше символов в место назначения, повреждая все, что находится в памяти после буфера назначения. Это проблема переполнения буфера, используемая во многих эксплойтах.
Также для функций POSIX API, таких как read()
который не помещает завершающий 0 в буфер, но возвращает количество прочитанных байтов, вы либо вручную поместите 0, либо скопируете его, используя strncpy()
,
В вашем примере кода, index
на самом деле не индекс, а count
- сообщает, сколько символов можно скопировать из источника в место назначения. Если среди первых n байтов источника нет нулевого байта, строка, помещенная в место назначения, не будет завершена нулем
Для меня самый чистый способ скопировать строку в другую и остановиться, если вы достигнете предела места назначения, - это snprintf.
#include <stdio.h>
#include <string.h>
int main()
{
char src[] = "Some example...";
char dest1[50], dest2[5];
snprintf(dest1, sizeof(dest1), "%s", src);
snprintf(dest2, sizeof(dest2), "%s", src);
printf("%s\n", dest1);
printf("%s\n", dest2);
return 0;
}
Выходы:
Some example...
Some
Но, возможно, не самый эффективный.
strncpy заполняет пункт назначения значением '\0' для размера источника, даже если размер пункта назначения меньше....
страница руководства:
Если длина src меньше n, strncpy() дополняет остаток dest нулевыми байтами.
и не только остаток... также после этого, пока не будет достигнуто n символов. И, таким образом, вы получаете переполнение... (см. Реализацию страницы руководства)
Это может использоваться во многих других сценариях, где вам нужно скопировать только часть вашей исходной строки в место назначения. Используя strncpy(), вы можете скопировать ограниченную часть исходной строки, в отличие от strcpy(). Я вижу, что код, который вы создали, взят из publib.boulder.ibm.com.
Это зависит от наших требований. Для пользователей Windows
Мы используем strncpy всякий раз, когда мы не хотим копировать всю строку или хотим копировать только n символов. Но strcpy копирует всю строку, включая завершающий нулевой символ.
Эти ссылки помогут вам узнать больше о strcpy и strncpy и о том, где мы можем их использовать.
strncpy - более безопасная версия strcpy. На самом деле вы никогда не должны использовать strcpy, потому что это потенциальная уязвимость переполнения буфера, которая делает вашу систему уязвимой для всех видов атак.