так что склонны к ошибкам.

ледующем относительноstrncpy: http://www.cplusplus.com/reference/clibrary/cstring/strncpy/упоминается следующее:

Никакой нулевой символ не добавляется неявно в конец пункта назначения, поэтому пункт назначения будет заканчиваться нулем только в том случае, если длина строки C в источнике меньше, чем num.

Что подразумевается под этим предложением?

 Matteo Italia22 янв. 2011 г., 15:22
Короче говоря: избегайте использованияstrncpy как безопасныйstrcpyЭто другая функция для другой цели, которая подвергает другим угрозам безопасности.
 James Greenhalgh22 янв. 2011 г., 15:28
Это помечено C ++ специально? Если вы используете C ++, я бы полностью избегал строковых функций C и использовал бы функции C ++ Std :: String. В противном случае я бы удалил тег C ++ ...
 R..22 янв. 2011 г., 15:47
cplusplus.com - сайт, наполненный не совсем понятными словами, вводящими в заблуждение и часто простыминеправильно Информация. Я бы избегал этого и вместо этого читал соответствующие документы по стандартам.
 paxdiablo22 янв. 2011 г., 15:32
Я не согласен с удалением тега @James, хотя не с вашим советом использовать «правильные» строки. Однако, хотя в подавляющем большинстве случаев лучше использовать строки C ++, все еще существуют ситуации, когда старые строки C могут быть полезны, и онинаходятся В конце концов, часть стандарта C ++.
 Steve Jessop22 янв. 2011 г., 15:49
Я второй нерекомендовать для cplusplus.com. Для всего, что находится в C, предпочитайте результаты поиска с opengroup.org cplusplus.com. Сравнивая их в этом примере, cplusplus.com не упоминает, что поведение не определено для перекрывающихся источника / назначения. Текст Opengroup взят из Posix и более или менее воспроизводит стандарт C. Для C ++ хорошую информацию в форме веб-страницы трудно найти, поэтому поиск в Интернете по именам нужных вам классов / функций и их поиск в книге. Или PDF стандарта.

Ответы на вопрос(6)

В C строки хранятся в виде массивовcharи они имеют нулевое окончание, что означает, что они имеют дополнительный0 добавлен в конце, который отмечает конец строки и может быть использован позже, чтобы выяснить длину строки. Итак, строка"hello" выглядит так в памяти:

char hello[] = {'h', 'e', 'l', 'l', 'o', 0};

Обычно, когда вы копируете строку,null персонаж должен быть скопирован. Таким образом, память, необходимая для буфера строк, имеет длину + 1 (например,(strlen(hello) + 1) * sizeof(char)).

функцияstrncpy позволяет копировать только столько символов, сколько можно уместить в предоставленном буфере. Если предоставленный вами буфер недостаточно велик, чтобы вместить этот дополнительныйnull, это не будет добавлено. Или, если строка обрезана, она не будет заканчиваться нулем.

char hello[] = "hello"; // 5 characters, 6 bytes long
char hel[3];
strncpy(hel, hello, 3); // hel is {'h', 'e', 'l'}

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

 detunized22 янв. 2011 г., 15:57
Хорошо, возможно, это должно было бытьsizeof(hello[0]).
 paxdiablo22 янв. 2011 г., 15:47
Пожалуйста, никогда* sizeof(char), он сокращает срок службы вашей клавиатуры с дополнительными нажатиями клавиш и ваш монитор с необходимыми дополнительными электронами :-)

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

"foo" имеет 3 символа + 1 нулевой терминатор (хранится как"foo\0") давая общую длину 4. Если вы звонитеstrncpy с участиемn=3 (или меньше) он не будет добавлять нулевой терминатор к концу целевой строки, но будет копировать только"foo", Попытка напечатать полученную строку приведет к неопределенному поведению из-за отсутствия нулевого терминатора, который сигнализирует об окончании строки.

Вы должны быть очень осторожны с этим и либо пройтиn один больше, чем максимальный источник, или добавьте нулевой терминатор самостоятельно.

strncpy(), даже когда они точно объяснены так, как они указаны в приведенной выше ссылке на C ++, широко понимаются неправильно. Поведение этой функции нелогично и подвержено ошибкам.

Чтобы избежать проблем при его использовании или в дальнейшем в процессе разработки, когда сопровождающий будет неправильно читать код и добавлять дополнительные тонкие ошибки, существует простое решение:НИКОГДА НЕ ИСПОЛЬЗУЙТЕ ЭТУ ФУНКЦИЮ.

Вы можете прочитать более подробную информацию об этом вэта статья Брюса Доусона.

Чтобы ответить на ваш вопрос: если исходная строка длиннее, чем размер, переданный в качестве третьего аргумента (обычно соответствующий размеру буфера назначения), функция скопирует символы размера в место назначения, и среди них не будет нулевого байта. призваниеstrlen(destination); затем вызовет неопределенное поведение, потому что оно будет пытаться читать за пределами массива, пока не найдет нулевой терминатор. Именно это специфическое поведение делаетstrncpy так что склонны к ошибкам.

Решение Вопроса

что, например, если ваша исходная строка содержит 20 символов плюс нулевой терминатор и вашstrncpy задает менее 21 символа, к целевой строке не будет добавлен ноль.

Это из-за того, как это работает:strncpy гарантирует, что он будет записывать ровно N байтов, где N - это значение длины, переданное в.

Если длина исходной строки (без нулевого байта) меньше этой, она заполнит область назначения нулями. Если оно равно или больше, вы не получите нулевое значение к месту назначения.

, что технически это может быть не строка C, которую вы получаете. Это можно решить с помощью кода вроде:

char d[11];          // Have enough room for string and null.
strncpy (d, s, 10);  // Copy up to 10 bytes of string, null the rest.
d[10] = '\0';        // Then append null manually in case s was too long.

Вы выделяете 11 байтов (индексы массива 0..10), копируете до 10 (индексы 0..9) и затем устанавливаете 11-й (индекс 10) в ноль.

Вот схема, показывающая три возможности записи строк различного размера в область из 10 символов сstrncpy (d, s, 10) где. представляет нулевой байт:

s              d
-------------  ----------
Hello.         Hello.....
Hello Fred.    Hello Fred
Hello George.  Hello Geor

Обратите внимание, что во втором и третьем случае нулевой байт не записывается, поэтому, если вы обрабатываетеd как строка, вы, вероятно, будете разочарованы в результате.

 Steve Jessop22 янв. 2011 г., 15:30
«Вы, вероятно, будете разочарованы в результате» - да, почему UB всегда глупые носовые демоны, а не, например, торт? Носовой пирог, то есть.
 Steve Jessop22 янв. 2011 г., 19:29
@bdonlan: или со вкусом носа.
 paxdiablo22 янв. 2011 г., 15:39
@Steve: ха-ха, хорошо. На самом деле, это может быть основой для целого вопроса (хотя, даже в случае CW, он, вероятно, будет закрыт): «Кто-нибудь когда-либо испытывал неопределенное поведение, которое былохороший? Нет, не только то, что он сделал то, что вы ожидали, но и то, что он вышел за рамки служебного долга ".
 bdonlan22 янв. 2011 г., 15:45
@ Стив, даже когда UB производит торт, я боюсь, что он имеет вкус демона
 Simplicity22 янв. 2011 г., 20:45
@paxdiablo. Спасибо за ваш ответ. Вы можете просто объяснить эту строку "d [10] = '\ 0';"? Тем более, что когда «s» слишком длинное, место «10» уже будет заполнено? Как я могу добавить «ноль» тогда? Благодарю.

num байты будут скопированы из исходного буфера в целевой буфер; так что если длина строки источника, если верхняя или равнаnumзавершающий байт NULL не будет скопирован, и в результате не будет завершающего байта NULL, что опасно.

Рекомендуется использоватьstrlcpy вместо.

 paxdiablo22 янв. 2011 г., 15:36
Рекомендовано кем? Разумеется, не излишне бодрые :-)мой Рекомендуется изучить все слабые стороны инструментов, которые вы используете, а не полагаться на костыли. Люди, которые хотят этого уровня безопасности, должны покинуть чудесную страну C и вернуться в Visual Basic :-) И, пожалуйста, обратите внимание на смайлики! Я не могу сказать, сколько аргументов у меня началось здесь с моим сухим чувством юмора :-)

Ваш ответ на вопрос