как правильно использовать strncpy? - PullRequest
0 голосов
/ 06 сентября 2018

Я знаю, strncpy является более безопасной версией strcpy, как сказано здесь .

Однако, когда я хочу скопировать из src в dst и dst не является чистым буфером, я получаю нежелательные результаты, которых можно избежать с помощью strcpy:

char *p = "123";
char a[10] = "aaaaaa";

strncpy(a,p,strlen(p));
printf("%s\n", a);   // 123aaa

strcpy(a,p);
printf("%s\n", a);   // 123 <- desired output, as the trailing a's are garbage

В моем реальном случае я знаю strlen(src) < sizeof(dst) (по крайней мере, если это не так, программа будет аварийно завершаться намного раньше), так что я могу спокойно strcpy.

Однако, если strncpy - это то, что я должен использовать, тогда я должен добавить после dst[strlen(src)] = '\0', чтобы избежать мусора (или, что еще лучше, инициализировать буфер заранее?)

Ответы [ 3 ]

0 голосов
/ 06 сентября 2018

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

Попытка использовать его вне специализированной ниши приводит к отвратительным искажениям и неэффективному коду.

Есть более подходящие способы сделать это, например, strlcpy() и / или вручную, используя strlen() и memcpy().

0 голосов
/ 06 сентября 2018

как правильно использовать strncpy?

Когда код должен скопировать строку в место назначения и допустить, что результат не является нулевым символом завершен и не полностью скопирован, используйте sizeof destination для аргумента размера:

char a[10];
// strncpy(a,p,strlen(p));
strncpy(a, p, sizeof a);

// printf("%s\n", a);
printf("%.*s\n", (int) sizeof a, a);

Если код хочет скопировать строку и обнаружить недостаточные проблемы с памятью с помощью strncpy() или если требуется заполнение нулевым символом '\0', также используйте sizeof destination.

char a[10];
strncpy(a, p, sizeof a);
if (a[sizeof a - 1] != '\0') {
  // insufficient memory
  // Maybe set last last character to the null character 
  a[sizeof a - 1] == '\0';
  // or other more robust handling
  return ERROR_INSUFFICIENT_MEMORY;
}

В противном случае не используйте strncpy()


Существуют более эффективные способы обнаружения недостаточного объема памяти, чем с помощью strncpy(), когда заполнение нулевым символом '\0' не требуется. strncpy() ноль заполняет остаток, если таковой имеется, не скопированного буфера. Ниже приведено много времени для заполнения нуля только для проверки недостаточности.

char a[1000];
strncpy(a, "abc", sizeof a);
if (a[sizeof a - 1] != '\0') {
  ....

Лучшие альтернативы используют strlen(), strlcpy(), memcpy(). @Deduplicator.

См. Также strncpy или strlcpy в моем случае .

Для стандартного однострочного C lib код может использовать snprintf() и строку обнаружения ошибок. Хороший компилятор должен был бы анализировать snprintf(a, sizeof a, "%s", p) и генерировать эффективный код.

// Copy with no overflow.
// 'a' is always null character terminated.
int len = snprintf(a, sizeof a, "%s", p);
if (len < 0 || (unsigned) len >= sizeof a) Report_truncated_copy();
0 голосов
/ 06 сентября 2018

Третий аргумент strncpy предназначен для представления размера целевого буфера . И когда он заполняет его, он не добавляет нулевой завершающий символ по дизайну.

Если у вас достаточно места для терминатора и вы настаиваете на strncpy, просто передайте strlen(p) + 1, чтобы он не предполагал, что он исчерпал целевой буфер.

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

...