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

我想知道考虑到最大量的字符,是否有更干净,更有效的方法来执行以下strncpy 。 我觉得自己太过分了。

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

我根本不会使用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; } 

首先,对于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 

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

 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!"; 

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

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

一旦它击中NUL, strncpy()将自动停止; 通过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); 

基本上你正在重新发明1996年引入的strlcpy – 请参阅由Todd C. Miller和Theo de Raadt 撰写的strlcpy和strlcat – 一致,安全,字符串副本和连接文章。 你可能还没有听说过它,因为它被glibc维护者称为“非常低效的BSD废话”而被拒绝加入glibc ,即使被所有其他操作系统采用,也被争取到今天 – 请参阅Damien Miller的Secure Portability论文(第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 , 2003/06/03 * Placed in the public domain. */ #include  /* 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可能需要很长时间,如果您不需要知道原始长度,那么第一个示例可能会更快。

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