Почему вы должны использовать 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 );

Который произвел этот вывод:

destination is originally = 'abcdefg'
After strcpy, destination becomes '123456789'

destination1 is originally = 'abcdefg'
After strncpy, destination1 becomes '12345fg'

Заставляет меня задаться вопросом, почему кто-то захочет этого эффекта. Похоже, это было бы странно. Эта программа заставляет меня думать, что вы можете в основном копировать имя кого-то (например, Tom Brokaw) с Tom Bro763.

В чем преимущества использования strncpy() над strcpy()?

Ответ 1

strncpy сражается с переполнением буфера, требуя, чтобы вы ввели в него длину. strcpy зависит от конечного \0, который может не всегда встречаться.

Во-вторых, почему вы выбрали только для того, чтобы скопировать 5 символов в 7-строчной строке, это выходит за рамки меня, но это вызывает ожидаемое поведение. Он копирует только первые символы n, где n - третий аргумент.

Функции n все используются как защитное кодирование против переполнения буфера. Используйте их вместо старых функций, таких как strcpy.

Ответ 2

Функция strncpy() была разработана с особой проблемой: манипулирование строками, хранящимися в виде исходных записей каталога UNIX. Они использовали массив фиксированного размера, а nul-terminator использовался, только если имя файла было короче, чем массив.

Что за двумя странностями strncpy():

  • Он не устанавливает nul-terminator в пункт назначения, если он полностью заполнен; и
  • Он всегда полностью заполняет пункт назначения, при необходимости nuls.

Для "более безопасного strcpy()" вам лучше использовать strncat() так:

if (dest_size > 0)
{
    dest[0] = '\0';
    strncat(dest, source, dest_size - 1);
}

Это всегда будет nul-завершать результат и не будет копировать больше, чем необходимо.

Ответ 3

Хотя я знаю намерение за strncpy, это не очень хорошая функция. Избегайте обоих. Поясняет Раймонд Чен.

Лично мой вывод состоит в том, чтобы избегать strncpy и всех его друзей, если вы имеете дело с нулевыми символами. Несмотря на "str" в имени, эти функции не создают строки с нулевым завершением. Они преобразуют строку с нулевым символом в буфере символов. Использование их там, где ожидается нулевая строка, поскольку второй буфер является неправильным. Вы не только получаете нулевое завершение, если источник слишком длинный, но если источник короткий, вы получаете ненужное заполнение нулями.

См. Также Почему strncpy небезопасен?

Ответ 4

strncpy НЕ безопаснее, чем strcpy, он просто торгует одним типом ошибок с другим. В C, когда вы работаете с строками C, вам нужно знать размер ваших буферов, нет никакого способа обойти его. strncpy был оправдан для справочной статьи, упомянутой другими, но в противном случае вы никогда не должны ее использовать:

  • Если вы знаете длину строки и буфера, зачем использовать strncpy? Это пустая трата вычислительной мощности в лучшем случае (добавление бесполезного 0)
  • если вы не знаете длины, тогда вы рискуете молча усекать свои строки, что не намного лучше переполнения буфера

Ответ 5

То, что вы ищете, это функция strlcpy(), которая всегда завершает строку с 0 и инициализирует буфер. Он также способен обнаруживать переполнения. Только проблема, это не (действительно) портативная и присутствует только на некоторых системах (BSD, Solaris). Проблема с этой функцией заключается в том, что она открывает еще одну банку червей, что видно из обсуждений на http://en.wikipedia.org/wiki/Strlcpy

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

EDIT: 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;
}

Ответ 6

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

Также для функций API POSIX, таких как read(), который не помещает завершение 0 в буфер, но возвращает количество прочитанных байтов, вы либо вручную поместите 0, либо скопируйте его с помощью strncpy().

В вашем примере кода index на самом деле не является индексом, но count - он сообщает, сколько символов не более для копирования из источника в пункт назначения. Если не существует нулевого байта среди первых n байтов источника, строка, помещенная в пункт назначения, не будет завершена нулем

Ответ 7

strncpy заполняет место назначения с помощью "\ 0" для размера источника, хотя размер места назначения меньше.

страница руководства:

Если длина src меньше n, strncpy() заполняет оставшуюся часть dest с нулевыми байтами.

а не только остаток... также после этого, пока n символов не будет достиг. И таким образом вы получаете переполнение... (см. Справочную страницу осуществление)

Ответ 8

Это может использоваться во многих других сценариях, где вам нужно скопировать только часть исходной строки в пункт назначения. Используя strncpy(), вы можете скопировать ограниченную часть исходной строки, а не strcpy(). Я вижу, что код, который вы положили, происходит от publib.boulder.ibm.com.

Ответ 9

Это зависит от нашего требования. Для пользователей Windows

Мы используем strncpy всякий раз, когда мы не хотим копировать целую строку, или мы хотим скопировать только n количество символов. Но strcpy копирует всю строку, включая завершение нулевого символа.

Эти ссылки помогут вам узнать больше о strcpy и strncpy и где мы можем использовать.

о strcpy

о strncpy

Ответ 10

strncpy - более безопасная версия strcpy, поскольку вы никогда не должны использовать strcpy, потому что ее потенциальная уязвимость переполнения буфера, которая делает вашу систему уязвимой для всех видов атак