在C中更有效地使用strncpy复制n个字符

时间:2012-05-03 04:27:46

标签: c string malloc strncpy

我想知道考虑到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] = '\0';
                } else {
                        strncpy (str, string, len);
                        str[len] = '\0';
                }
                printf("%s\n", str);
        }
        return 0;
}

6 个答案:

答案 0 :(得分:6)

我根本不会使用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] = '\0';
    }
    // if we copied the string, return it; otherwise, return the null pointer 
    // to indicate failure.
    return buffer;
}

答案 1 :(得分:3)

首先,对于strncpy,“没有空字符隐式附加到目标的末尾,因此如果源中的C字符串的长度小于num,则目标将仅以空值终止。”

我们使用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

答案 2 :(得分:0)

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

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] = '\0';
        printf("%s\n", str);
    }
    return 0;
}

你没有太多办法可以进一步加快strncpy()的速度。您可以使用以下方法减少时间:

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

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

请注意,如果最大大小很大且要复制的字符串很小,那么strncpy()在目标字符串中的每个未使用位置上写入空值的事实可能会使事情变慢。

答案 3 :(得分:0)

一旦它到达NUL,

strncpy()将自动停止;在没有检查的情况下通过max就足够了。

答案 4 :(得分:0)

我认为这已经足够了:

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);

答案 5 :(得分:0)

基本上你正在重新发明1996年引入的strlcpy - 参见Todd C. Miller和Theo de Raadt撰写的strlcpy and strlcat - consistent, safe, string copy and concatenation论文。您可能没有听说过它,因为它是refused to be added to glibc,被glibc维护者称为“非常低效的BSD垃圾”,即使被所有其他操作系统采用也一直争斗到今天 - 参见Secure Portability论文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++) == '\0')
            break;
    }
}

/* Not enough room in dst, add NUL */
if (n == 0) {
    if (max != 0)
        *d = '\0';      /* NUL-terminate dst */
}

以下是http://cantrip.org/strlcpy.c上使用memcpy:

的strlcpy版本
/*
 * 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可能需要很长时间,如果您不需要知道原始长度,那么第一个示例可能会更快。

这一切都取决于您的数据,因此对实际数据进行分析是唯一可以找到的方法。