创建C子串:使用赋值运算符VS strncopy循环,哪个更好?

时间:2012-09-05 14:24:44

标签: c substring assignment-operator strncpy

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

#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

参考:Strings in c, how to get subStringHow to get substring in CDifference between strncpy and memcpy?

4 个答案:

答案 0 :(得分:4)

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

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

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

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

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

我的建议:

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

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

答案 1 :(得分:3)

虽然这看似违反直觉,但是复制字符串比使用循环中的赋值运算符有更多优化方法。例如,IA-32为REPMOVSSTOS等提供CMPS前缀用于字符串处理,这些可以比复制一个char的循环快得多一次。 strncpystrcpy的实施可能会选择使用此类硬件优化代码来实现更好的性能。

答案 2 :(得分:1)

只要您知道自己的长度在“范围内”并且所有内容都已正确终止,那么strncpy会更好。

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

答案 3 :(得分:0)

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

但是,请注意strncpy不是一个圆润的轮子。特别是,如果字符串太长,则不会向目标附加空字节。 BSD函数strlcpy设计得更好,但并不是随处可用。甚至strlcpy is not a panacea:您需要正确获取缓冲区大小,并注意它可能会截断字符串。

复制字符串的可移植方法是,如果字符串太长则截断,是调用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;