Я мог бы указать вам на страницы руководства, веб-сайты и т. Д., Но в конечном итоге важен сам стандарт C. Как часть стандартной библиотеки времени выполнения, использование и поведение определены в C99-§7.23.2.4 как:
#include <string.h>
char *strncpy(char * restrict s1,
const char * restrict s2,
size_t n);
Описание Функция strncpy
копирует не более n символов (символы, следующие за нулевым символом, не копируются) из массива, на который указывает s2, в массив, на который указывает s1. Если копирование происходит между перекрывающимися объектами, поведение не определено. Если массив, на который указывает s2, является строкой, которая короче n символов, нулевые символы добавляются к копии в массиве, на который указывает s1, пока не будут записаны n символов всего.
Возвращает. Функция strncpy
возвращает значение s1.
Здесь имеется важная подразумеваемая информация, наиболее важной из которых является: strncpy()
НЕ завершает вашу целевую строку нулевым символом, если длина исходной строки (не включая ее завершающий нулевой символ) соответствует или превышает указанную длину целевого буфера).
Более того, хотя это четко указано в стандарте (см. Выше), меня продолжает сбивать с толку, сколько инженеров НЕ знают, что strncpy()
заполняет строковый буфер назначения нулевыми символами до тех пор, пока не будет достигнута указанная длина n
когда длина исходной строки меньше, чем размер целевого буфера. Отсюда следует неизбежный вывод:
API strncpy()
ВСЕГДА будет записывать n
символов в указанный адрес по целевому буферу.
В вашем случае, поскольку целевой буфер имеет ширину всего 10 символов, вы пишете 90 дополнительных символов после определенного конца доступной для записи памяти и, таким образом, попадаете в страну неопределенного поведения.
В этот момент вы должны спросить себя: «Так в чем же польза?» Это , возможно, фундаментальный вариант использования. Это позволяет вам копировать до n
символов в целевой буфер с предсказуемостью, зная, что вы не перейдете за n
символов. Период. Однако в конечном итоге вам нужна строка с завершающим нулем, поэтому правильное использование таково:
char dst[ N ];
strncpy(dst, src, N-1);
dst[N-1] = 0;
где N
- жесткая длина dst
буфера в символах, которая больше или равна 1
. Обратите внимание, что dst
также может быть указателем динамически выделяемой памяти:
char *dst = malloc( N * sizeof(char) );
strncpy(dst, src, N-1);
dst[N-1] = 0;
С учетом вышеизложенного у вас будет всегда строка с завершающим нулем в dst
. Если исходная строка length меньше указанной длины целевого буфера, strncpy()
будет заполнять остальную часть буфера нулевыми символами до тех пор, пока общее количество исходных символов-скопированных + хвостовых-заполненных-нулевых- символов равно n
, и последний оператор является избыточным. Если длина исходной строки равна или больше длины целевого буфера, strncpy()
прекратит копирование по достижении N-1
символа, а последний оператор устанавливает нулевой символ в конце буфера. Это приводит к «сокращенной» строке префикса исходного источника, но, что наиболее важно, это гарантирует, что вы НЕ выйдете за границы вашего целевого буфера с последующим вызовом строкового API, который сканирует терминатор.
Полезность описанной выше техники всегда остается спорной. Я парень C ++, поэтому std::string
спасает меня от всего этого безумия. Но реальность такова: иногда вас волнует, не скопировано ли src
полностью целиком в dst
; иногда нет. Полезность очень ситуативно зависит. Для представления строковых данных в пользовательском интерфейсе это (скорее всего) не имеет значения. Для копирования строки, которая будет использоваться для критических данных, подстрока с частичным префиксом неприемлема. Когда полиция выдаст ордер на арест «Джозефа Джонсона-младшего», будут некоторые объяснения, что делать, когда его отца («Джозеф Джонсон») тащат в тюрьму, потому что в именном буфере программного обеспечения для выдачи ордеров содержалось только 15 символов. .
С учетом всего сказанного, ваша ошибка сегментации сводится к следующему утверждению:
strncpy(s1.from_str,src, 100); // length parameter is wrong.
Вспомните заявление, выделенное жирным шрифтом выше: «strncpy()
ВСЕГДА будет записывать n
символов по адресу, указанному в целевом буфере.». Это означает, что приведенный выше код всегда будет записывать 100 символов в целевой буфер, который в вашем случае имеет ширину всего 10 символов, поэтому поведение undefined и, вероятно, ker-boom em >.
Исправьте это, выполнив следующие действия, если целевой буфер представляет собой массив символов фиксированной длины:
strncpy(s1.from_str,src, sizeof(s1.from_str)/sizeof(s1.from_str[0])-1);
s1.from_str[ sizeof(s1.from_str)/sizeof(s1.from_str[0])-1 ] = 0;
См. Предыдущее использование, чтобы узнать, как это сделать для динамической строки длиной `N символов.
person
WhozCraig
schedule
28.12.2012