4

这可能有点毫无意义,但我很好奇你们对此有何看法。我正在使用指针迭代一个字符串,并希望从中提取一个短子字符串(将子字符串放入预先分配的临时数组中)。是否有任何理由在 strncopy 上使用赋值,反之亦然?IE

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{   char orig[]  = "Hello. I am looking for Molly.";

    /* Strings to store the copies
     * Pretend that strings had some prior value, ensure null-termination */
    char cpy1[4] = "huh\0";
    char cpy2[4] = "huh\0";

    /* Pointer to simulate iteration over a string */
    char *startptr = orig + 2;
    int length = 3;
    int i;

    /* Using strncopy */
    strncpy(cpy1, startptr, length);

    /* Using assignment operator */
    for (i = 0; i < length; i++)
    {   cpy2[i] = *(startptr + i); 
    }   

    /* Display Results */
    printf("strncpy result:\n");
    printf("%s\n\n", cpy1);
    printf("loop result:\n");
    printf("%s\n", cpy2);
}   

在我看来, strncopy 的输入更少而且更容易阅读,但我看到人们提倡使用循环。有区别吗?这还重要吗?假设这是针对 i (0 < i < 5) 的小值,并且保证了空终止。

参考:c 中的字符串,如何获取子字符串,如何获取 C 中的子字符串, strncpy 和 memcpy 之间的区别?

4

4 回答 4

4

strncpy(char * dst, char *src, size_t len)有两个特殊的性质:

  • if (strlen(src) >= len): 结果字符串不会以 nul 结尾。
  • if (strlen(src) < len): 字符串的末尾将用 '\0' 填充/填充。

第一个属性将迫使您实际检查是否(strlen(src) >= len)并采取适当的行动。(或将最终字符粗暴地设置为 nul dst[len-1] = '\0';,就像上面的@Gilles 所做的那样)另一个属性并不是特别危险,但可能会溢出很多循环。想象:

char buff[10000];
strncpy(buff, "Hello!", sizeof buff);

它触及 10000 个字节,其中只需要触及 7 个字节。

我的建议:

  • A:如果你知道尺寸,就做memcpy(dst,src,len); dst[len] = 0;
  • B:如果您不知道大小,请以某种方式获取它们(使用 strlen 和/或 sizeof 和/或为动态分配的内存分配的大小)。然后:转到上面的 A。

由于为了安全操作 strncpy() 版本已经需要知道大小(以及对它们的检查!),所以 memcpy() 版本并不比 strncpy() 版本更复杂或更危险。(从技术上讲,它甚至更快;因为 memcpy() 不必检查 '\0' 字节)

于 2012-09-05T15:24:06.277 回答
3

虽然这似乎违反直觉,但复制字符串的方法比在循环中使用赋值运算符更优化。例如,IA-32 为字符串处理提供了,等REP前缀MOVS,这些前缀比一次复制一个字符的循环要快得多。实现或者可以选择使用这样的硬件优化代码来获得更好的性能。STOSCMPSstrncpystrcpy

于 2012-09-05T14:29:06.950 回答
1

只要您知道您的长度在“范围内”并且所有内容都正确地以 nul 终止,那就strncpy更好了。

如果您需要在那里进行长度检查等,循环可能会更方便。

于 2012-09-05T14:29:05.800 回答
0

带有分配的循环是一个坏主意,因为您正在重新发明轮子。您可能会犯错误,并且您的代码可能比标准库中的代码效率低(某些处理器已针对内存副本优化指令,并且优化的实现通常至少在可能的情况下逐字复制)。

但是,请注意,这strncpy不是一个全面的轮子。特别是,如果字符串太长,它不会将空字节附加到目标。BSD 功能strlcpy设计得更好,但并非随处可用。Evenstrlcpy 不是灵丹妙药:您需要正确设置缓冲区大小,并注意它可能会截断字符串。

复制字符串的一种可移植方法(如果字符串太长则截断)是调用strncpy并始终添加终止空字节。如果缓冲区是一个数组:

char buffer[BUFFER_SIZE];
strncpy(buffer, source, sizeof(buffer)-1);
buf[sizeof(buffer)-1] = 0;

如果缓冲区由指针和大小给出:

strncpy(buf, source, buffer_size-1);
buf[buffer_size-1] = 0;
于 2012-09-05T14:38:19.310 回答