Почему вы должны использовать strncpy вместо strcpy? - PullRequest
75 голосов
/ 11 августа 2009

Редактировать: я добавил источник для примера.

Я наткнулся на этот пример :

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'

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

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

Ответы [ 10 ]

159 голосов
/ 11 августа 2009

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

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

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

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

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

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

88 голосов
/ 11 августа 2009

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

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

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

30 голосов
/ 11 августа 2009

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

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

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

27 голосов
/ 11 августа 2009

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

  • если вы знаете длину вашей строки и буфера, зачем использовать strncpy? В лучшем случае это пустая трата вычислительных мощностей (добавление бесполезных 0)
  • если вы не знаете длины, то вы рискуете молча обрезать ваши строки, что не намного лучше, чем переполнение буфера
21 голосов
/ 11 августа 2009

Вам нужна функция 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;
}
3 голосов
/ 11 августа 2009

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

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

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

1 голос
/ 01 ноября 2013

strncpy заполняет пункт назначения '\ 0' для размера источника, даже если размер пункта назначения меньше ....

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

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

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

0 голосов
/ 24 мая 2016

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

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

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

о силе

о силе

0 голосов
/ 11 августа 2009

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

0 голосов
/ 11 августа 2009

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

...