Почему strncpy () не соблюдает заданный size_t n, равный 10 в temp2? - PullRequest
1 голос
/ 15 января 2020

Эта проблема поражает меня ... Может кто-нибудь, пожалуйста, разобраться с проблемой, потому что я уже потратил часы на это ..; (

#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\n", temp1);

  strncpy(temp2, temp1, 10);
  printf("%s\n", temp2);
  return 0;
}

Результат

Iam pretty much big string.
Iam prettyIam pretty much big string.

Ожидаемый результат:

Iam pretty much big string.
Iam pretty

Ответы [ 5 ]

4 голосов
/ 15 января 2020

Функция strncpy равна с учетом установленного вами ограничения в 10 байт.

Копирует первые 10 байтов из string в temp2. Ни один из этих 10 байтов не является нулевым байтом, а размер temp2 равен 10, поэтому в temp2 нет нулевых байтов. Когда вы затем передаете temp2 в printf, он читает после конца массива, вызывая неопределенное поведение .

Вам необходимо установить размер, заданный strncpy для размер массива - 1, затем вручную добавьте нулевой байт в конец.

strncpy(temp2, temp1, sizeof(temp2)-1);
temp2[sizeof(temp2)-1] = 0;
4 голосов
/ 15 января 2020

Цитирование соответствующего тега [strncpy] в переполнении стека { ссылка }, которое может помочь вам понять, что именно происходит:


Эту функцию не рекомендуется использовать ни для каких целей, ни в 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.

4 голосов
/ 15 января 2020

Вы вызываете Неопределенное поведение , пытаясь напечатать temp2, так как temp2 не завершается нулем . From man strncpy:

" Предупреждение: Если среди первых n байтов sr c нет нулевого байта, строка, помещенная в dest, не будет нулевой прекращается «. (выделено в оригинале)

См. также Стандарт C11 - 7.24.2.4 Функция strncpy (в частности, сноска: 308)

Итак temp2 не завершается нулем.

4 голосов
/ 15 января 2020

Адрес temp2 находится непосредственно перед адресом temp1, и поскольку вы не копируете окончательный 0, printf продолжит печать после окончания temp2. ​​

Как только время Вы не вставляете 0, результат printf не определен.

3 голосов
/ 15 января 2020

Из справочной страницы для strncpy():

Предупреждение : если среди первых n байтов sr c нет нулевого байта, строка помещается в dest не будет заканчиваться нулем.

Либо ваш вход короче, чем предоставленная длина, вы добавляете завершающий нулевой байт самостоятельно, либо его там не будет. printf() ожидает, что строка будет должным образом завершена нулем, и, следовательно, заполняет ваш выделенный буфер.

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

...