回到基础 - 将字符串复制到静态数组的惯用方法

时间:2010-12-06 05:24:41

标签: c++ c printf

好吧,strncpy不适用于NULL终止字符串 - 它不是为NULL终止字符串设计的(如果dest太短,它不会被NULL终止,如果dest更长,它将被填充零())。

所以,这是一个简单的代码:

const char *src = ....; // NULL terminated string of unknown length
char dest[30];

如何 src dest strcpy不安全,strncpy也是不好的选择。所以我离开了 strlen ,然后是memcpy? 我想解决方案会有所不同,每当我关心 dest 不会被截断( dest 小于 src 的长度)时。

一些限制:

  • 传统代码,所以我不想也不能将其更改为std :: string
  • 我没有strlcpy - gcc不提供它。
  • 代码可以在性能至关重要的应用程序部分中使用(例如,我不想像strncpy那样用零 dest 来浪费CPU时间填充。但是,我不是在谈论过早优化,而是用C语言执行字符串复制的愚蠢方式。

修改

Oopps,我的意思是strncpy而不是snprintf。我的错误

7 个答案:

答案 0 :(得分:4)

使用strncpy

strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';

这个填充零,但格式化工作比snprintf少得多。如果你真的必须让计算机做得尽可能少,请自己描述一下:

char* last = dest + sizeof(dest) - 1;
char* curr = dest; /* assuming we must not alter 'dest' */
while (curr != last && *src) { *curr++ = *src++; }
*last = '\0'; /* avoids a branch, but always writes.
If branch prediction is working well and the text normally fits:
if (curr == last) { *curr = '\0'; } */

答案 1 :(得分:4)

我认为你在谈论strncpy(),它可能不会终止字符串并用零填充缓冲区的其余部分。

snprintf()总是终止目标字符串(只要缓冲区的大小至少为1),并且不用零填充缓冲区的剩余部分。

总之,snprintf() 你想要的,除非你非常关心性能。由于snprintf()需要解释格式字符串(即使它最终完成的是复制字符串),对于有界字符串复制操作,最好使用strlcpy()之类的东西。

(如果你想要strlcpy()但没有它,你可以得到相当简单的source here。为了完整性,strlcat() is here

答案 2 :(得分:3)

如果您不关心截断,可以使用strncat()

dest[0] = 0;
strncat(dest, src, sizeof dest - 1);

答案 3 :(得分:1)

我只是自己动手:

for (int i = 0; i < (sizeof(dest) - 1) && src[i] != NULL; i++)
{
    dest[i] = src[i];
}
dest[i] = NULL;

这可确保dest以空值终止,但绝不会添加超出必要的空值。如果您确实对性能敏感,可以将其声明为公共标头中的宏或内联函数。

答案 4 :(得分:1)

使用snprintf。它始终为null终止,并且不执行任何空填充。不知道你对它有什么误解......

答案 5 :(得分:0)

std::copy(src, src+strlen(src)+1, dest)

答案 6 :(得分:0)

我不确定我是否完全理解你的问题,但如果你担心零填充,如果你像这样初始化你的数组,通常可以非常有效地完成。

char dest[30] = { 0 };

如果你初始化它就像你不必关心额外的逻辑来将'\ 0'添加到字符串的末尾,它甚至可能更快。

但是,如果您要进行优化,请记住在优化之前和之后测量性能。否则始终会考虑可读性和可维护性。