Эта проблема поражает меня ... Может кто-нибудь, пожалуйста, разобраться с проблемой, потому что я уже потратил часы на это ..; (
#include <stdio.h>
#include <string.h>
int main(){
char string[] = "Iam pretty much big string.";
char temp1[50];
char temp2[10];
// strcpy() and strncpy()
strcpy(temp1, string);
printf("%s
", temp1);
strncpy(temp2, temp1, 10);
printf("%s
", temp2);
return 0;
}
Результат
Iam pretty much big string.
Iam prettyIam pretty much big string.
Ожидаемый результат:
Iam pretty much big string.
Iam pretty
Всего 5 ответов
Функция strncpy
соблюдает установленный вами предел в 10 байт.
Он копирует первые 10 байтов из string
в temp2
. Ни один из этих 10 байтов не является нулевым байтом, а размер temp2
равен 10, поэтому в temp2
нет нулевых байтов. Когда вы затем передаете temp2
в printf
, он читает после конца массива, вызывая неопределенное поведение .
Вам необходимо установить размер, заданный для strncpy
размеру массива - 1, а затем вручную добавить нулевой байт в конец.
strncpy(temp2, temp1, sizeof(temp2)-1);
temp2[sizeof(temp2)-1] = 0;
Адрес temp2
находится непосредственно перед адресом temp1
и, поскольку вы не копируете последний 0
, printf продолжит печать после окончания temp2.
Как только вы не вставите 0
, результат printf
будет неопределенным.
Вы вызываете неопределенное поведение, пытаясь напечатать temp2
как temp2
не завершается temp2
. От man strncpy
:
« Предупреждение: если среди первых n байтов src нет нулевого байта, строка, помещенная в dest, не будет заканчиваться нулем.» (акцент в оригинале)
См. Также Стандарт C11 - 7.24.2.4 Функция strncpy (в частности, сноска: 308)
Так что temp2
не имеет temp2
завершения.
Из справочной страницы для strncpy()
:
Предупреждение : если среди первых n байтов src нет нулевого байта, строка, помещенная в dest, не будет заканчиваться нулем.
Либо ваш ввод короче указанной длины, либо вы добавляете завершающий нулевой байт самостоятельно, либо его там не будет. printf()
ожидает, что строка будет правильно завершена нулем, и, таким образом, заполняет ваш выделенный буфер.
Это только показывает, что n
вариантов многих стандартных функций ни в коем случае не безопасны. Вы должны прочитать их соответствующие справочные страницы и, в частности, посмотреть, что они делают, когда предоставленной длины недостаточно.
Ссылка на соответствующий тег [strncpy]
в переполнении стека https://stackoverflow.com/tags/strncpy/info , который может помочь вам понять, что именно происходит:
Эту функцию не рекомендуется использовать для каких-либо целей, ни в C, ни в C ++. Он никогда не задумывался как «безопасная версия strcpy
», но часто используется для таких целей. На самом деле он считается гораздо более опасным, чем strcpy
, так как нулевой механизм завершения strncpy
не интуитивен и поэтому часто неправильно понимается. Это из-за следующего поведения, определенного ISO 9899: 2011 7.24.2.4:
char *strncpy(char * restrict s1, const char * restrict s2, size_t n);
/ - /
3 Если массив, на который указывает s2, является строкой, которая короче, чем n символов, нулевые символы добавляются к копии в массиве, на который указывает s1 , до тех пор, пока все n символов не будут записаны.
Очень распространенной ошибкой является передача s2
который является точно таким же количеством символов, что и параметр n
, и в этом случае s1
не завершится нулем. То есть: strncpy(dst, src, strlen(src));
/* MCVE of incorrect use of strncpy */
#include <string.h>
#include <stdio.h>
int main (void)
{
const char* STR = "hello";
char buf[] = "halt and catch fire";
strncpy(buf, STR, strlen(STR));
puts(buf); // prints "helloand catch fire"
return 0;
}
Рекомендуемая практика в C состоит в том, чтобы заранее проверить размер буфера и затем использовать strcpy()
, или memcpy()
. Рекомендуемая практика в C ++ - использовать вместо std::string
.