在 C 语言中更有效地复制 n 个字符



我想知道是否有一种更干净、更有效的方法来完成以下strncpy,考虑到max数量的字符。我觉得做得太过分了。

int main(void)
{
        char *string = "hello world foo!";
        int max = 5;
        char *str = malloc (max + 1);
        if (str == NULL)
                return 1;
        if (string) {
                int len = strlen (string);
                if (len > max) {
                        strncpy (str, string, max);
                        str[max] = '';
                } else {
                        strncpy (str, string, len);
                        str[len] = '';
                }
                printf("%sn", str);
        }
        return 0;
}

我根本不会为此使用strncpy。至少如果我理解你想做什么,我可能会做这样的事情:

char *duplicate(char *input, size_t max_len) {
    // compute the size of the result -- the lesser of the specified maximum
    // and the length of the input string. 
    size_t len = min(max_len, strlen(input));
    // allocate space for the result (including NUL terminator).
    char *buffer = malloc(len+1);
    if (buffer) {
        // if the allocation succeeded, copy the specified number of 
        // characters to the destination.
        memcpy(buffer, input, len);
        // and NUL terminate the result.
        buffer[len] = '';
    }
    // if we copied the string, return it; otherwise, return the null pointer 
    // to indicate failure.
    return buffer;
}

首先,对于strncpy,"没有空字符隐式附加到目标的末尾,因此只有当源中C字符串的长度小于num时,目的地才会被null终止。

我们使用 memcpy((,因为 strncpy(( 在每个副本上检查每个字节是否有 0。我们已经知道字符串的长度,memcpy(( 做得更快。

首先计算字符串的长度,然后决定要分配和复制的内容

int max = 5;               // No more than 5 characters
int len = strlen(string);  // Get length of string
int to_allocate = (len > max ? max : len); // If len > max, it'll return max. If len <= max, it'll return len. So the variable will be bounded within 0...max, whichever is smaller
char *str = malloc(to_allocate + 1); // Only allocate as much as we need to
if (!str) { // handle bad allocation here }
memcpy(str,string,to_allocate); // We don't need any if's, just do the copy. memcpy is faster, since we already have done strlen() we don't need strncpy's overhead
str[to_allocate] = 0; // Make sure there's a null terminator
基本上,

你正在重新发明1996年推出的strlcpy - 参见Todd C. Miller和Theo de Raadt的strlcpy和strlcat-一致,安全,字符串副本和连接论文。你可能没有听说过它,因为它被拒绝添加到glibc中,被glibc维护者称为"非常低效的BSD废话",即使被所有其他操作系统采用,也一直战斗到今天 - 参见Damien Miller的安全可移植性论文(第4部分:选择正确的API(。

您可以使用libbsd项目(打包在Debian,Ubuntu和其他发行版上(在Linux上使用strlcpy,或者简单地复制在Web上容易找到的源代码(例如,在本答案中的两个链接上(。

但是回到你的问题,在你的情况下什么最有效,你在这里不使用源字符串长度是我的想法,基于OpenBSD的strlcpy源,http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/string/strlcpy.c?rev=1.11 但没有检查原始字符串的长度,它可能很长,但仍然有正确的"\0"结尾:

char *d = str;            // the destination in your example
const char *s = string;   // the source in your example
size_t n = max;           // the max length in your example
/* Copy as many bytes as will fit */
if (n != 0) {
    while (--n != 0) {
        if ((*d++ = *s++) == '')
            break;
    }
}
/* Not enough room in dst, add NUL */
if (n == 0) {
    if (max != 0)
        *d = '';      /* NUL-terminate dst */
}

以下是使用 memcpy 的 strlcpy 版本 http://cantrip.org/strlcpy.c:

/*
 * ANSI C version of strlcpy
 * Based on the NetBSD strlcpy man page.
 *
 * Nathan Myers <ncm-nospam@cantrip.org>, 2003/06/03
 * Placed in the public domain.
 */
#include <stdlib.h>  /* for size_t */
size_t
strlcpy(char *dst, const char *src, size_t size)
{
    const size_t len = strlen(src);
    if (size != 0) {
        memcpy(dst, src, (len > size - 1) ? size - 1 : len);
        dst[size - 1] = 0;
    }
    return len;
}

我认为哪一个更有效取决于源字符串。对于很长的源字符串,strlen 可能需要很长时间,如果您不需要知道原始长度,那么第一个示例对您来说可能会更快。

这一切都取决于您的数据,因此对真实数据进行分析将是找出答案的唯一方法。

您可以通过以下方式减少代码量:

int main(void)
{
    char *string = "hello world foo!";
    int max = 5;
    char *str = malloc(max + 1);
    if (str == NULL)
        return 1;
    if (string) {
        int len = strlen(string);
        if (len > max)
            len = max;
        strncpy(str, string, len);
        str[len] = '';
        printf("%sn", str);
    }
    return 0;
}

您无能为力来进一步加快strncpy()。 您可以通过使用以下方法减少时间:

char string[] = "hello world foo!";

然后改用sizeof(string)来避免strlen()

请注意,如果最大大小很大并且要复制的字符串很小,那么strncpy()在目标字符串中的每个未使用位置写入 null 这一事实确实会减慢速度。

一旦

strncpy()命中 NUL,它将自动停止;通过max而不检查就足够了。

我相信

这就足够了:

char *str = malloc(max+1);
if(! str)
return 1;
int len = strlen(string);  
memset(str, 0, max+1);
int copy = len > max ? max : len;
strncpy(str, string, copy);

相关内容

  • 没有找到相关文章

最新更新