strncpy не работает должным образом

#include <iostream>
using namespace std 
#include <string.h>
int main(){
    char token[] = "some random string";
    char c[23];  
    strcpy( c, token);
    strncpy(c, token, 5); 
    c[strlen(c)] = '\0';
    cout<<c;
    return 0 ;
}

Мой результат: some random string. Но я ожидаю, что это будет: some. Кто-нибудь может объяснить, почему он так себя ведет?


person Viku    schedule 25.12.2012    source источник
comment
Я рекомендую использовать std::string.   -  person Rapptz    schedule 25.12.2012


Ответы (4)


Я думаю, что ваш результат должен быть «какой-то случайной строкой», потому что ваши две строки кода ничего не делают, см. Комментарий.

int main(){
   char token[] = "some random string";
   char c[23];  
   strcpy( c, token);
   strncpy(c, token, 5);  // Does nothing
   c[strlen(c)] = '\0';   // Does nothing
   cout<<c;
   return 0 ;
}

Если вы хотите вывести «some», вы можете сделать это:

strncpy(c, token, 5);
c[5] = '\0';

strncpy () не добавляет автоматически завершающий '\ 0' в строку dest. Если длина исходной строки больше len (3-й аргумент strncpy), то len символов копируется в dest без завершающего символа '\ 0'. Таким образом, вы должны явно указать завершающий '\ 0' кодом.

person TieDad    schedule 25.12.2012
comment
После выполнения strncpy (c, token, 5) значение c должно быть некоторым. пожалуйста, поправьте, если я ошибаюсь. - person Viku; 25.12.2012
comment
strncpy () не добавляет автоматически завершающую строку '\ 0' в целевую строку. Если длина исходной строки больше len (3-й аргумент strncpy), то до len символов копируется в dest без хвоста '\ 0'. Таким образом, вы должны явно указать конец '\ 0' по коду. - person TieDad; 25.12.2012
comment
если мне нужно явно указать '\ 0'. Затем я могу получить вывод, сделав c [4] = '\ 0' без вызова strncpy (..). Тогда в чем важность strncpy (...); - person Viku; 25.12.2012
comment
strncpy используется для предотвращения переполнения буфера назначения. strcpy не заботится о размере буфера назначения, он не перестанет копировать символы в адрес назначения, пока не найдет '\ 0'. - person TieDad; 25.12.2012
comment
За этот ответ следует наградить медалью! Спасибо. - person Vishal Anand; 23.02.2019

Он работает нормально - имейте в виду, что strncpy не обязательно завершает строку нулем . Когда вы это сделаете:

strncpy(c, token, 5);

Он копирует первые 5 байтов token в c , но не завершает результат нулевым символом. Кроме того, эта строка бесполезна:

c[strlen(c)] = '\0';

strlen(c) ищет существующий нулевой терминатор, и, как только вы его находите, вы заменяете его другим нулевым ограничителем, что бессмысленно.

В новом коде strncpy следует редко, если вообще. Его предполагаемое использование (буферы фиксированной длины, которые не обязательно заканчиваются нулем) давно устарело. Вместо этого отдайте предпочтение такой функции, как strlcpy (примечание: strlcpy не является стандартным; он доступен только в BSD-подобных системах).

Или, если вы кодируете на C ++ вместо чистого C, просто используйте std::string и вообще избегайте сложных проблем, подобных этой.

person Adam Rosenfield    schedule 25.12.2012
comment
если мне нужно явно указать '\ 0'. Затем я могу получить вывод, сделав c [4] = '\ 0' без вызова strncpy (..). Тогда в чем важность strncpy (...); - person Viku; 25.12.2012
comment
Важность strncpy заключается в том, чтобы избежать переполнения буфера. Подумайте, что бы произошло, если бы целевой буфер был меньше исходной строки. - person drescherjm; 25.12.2012
comment
Хотя я поддерживаю рекомендацию. Если это C ++, я бы избегал использования любого из них и вместо этого использовал std :: string. - person drescherjm; 25.12.2012

Вам нужно завершать нуль после слова "some" вместо того, чтобы завершать нуль после всей строки. strncpy скопирует "some" в c, но это не обязательно завершает вашу строку нулем (см. справочную страницу для strncpy)

c[4] = '\0'
person Klarth    schedule 25.12.2012

Как уже упоминалось, в отличие от snprintf до sprintf, strncpy не является более безопасной версией strcpy. Это просто гарантирует, что «точно N символов копируется в место назначения (используйте NUL, если исходная строка короче N)». (страница руководства)

Но я думаю, вы уже заметили, что по строчке

c[strlen(c)] = '\0';

Это означало обеспечить нулевое завершение c. Но на самом деле это бессмысленно, поскольку strlen использует NUL для определения длины c. Таким образом, эта строка почти не означает «найти NUL и записать NUL в это место».

Важность strncpy состоит в том, чтобы скопировать определенную часть строки. Это не исправление для strcpy, оно существовало до введения snprintf функций.

person timothyqiu    schedule 25.12.2012