【问题标题】:How to find the size of a C string without using a while loop?如何在不使用 while 循环的情况下找到 C 字符串的大小?
【发布时间】:2020-06-01 10:44:28
【问题描述】:

我最近试图找到输入 C 字符串缓冲区的大小,以便在 memcpy 中使用它来将输入缓冲区的内容复制到输出缓冲区而不重叠。 下面是代码sn-p。

char * func(char *buff1, char *buff2, char *outbuff)
{
    int size = 0;
    while(*buff1 != '\0')
     {
       size++;
       buff1++;
     }
   memcpy(outbuff, buff1, sizeof(char)*size);
   memcpy(outbuff + size, buff2, sizeof(char)*size);
   return outbuff; 
}

但是,我发现这是一种非常低效的查找大小的方法。如果你们知道任何其他替代方案,那将对我非常有帮助。

编辑:我不允许将它们的大小作为单独的参数传递。

【问题讨论】:

  • 可能最有效的方法是在填充输入缓冲区时记住大小,并将其作为附加参数传递给func
  • 我无法将它们的大小作为单独的参数传递。 — 为什么不呢?
  • @DanielLangr 这是给我的要求。我们可以在不使用 while 循环的情况下以更有效的方式做到这一点吗?
  • @user207421 在不使用任何循环的意义上是高效的,更像是一种矢量化方式。
  • @SauravRai 首先,我们需要了解您的任务和解决方案的要求。另外,请创建一个我们可以运行的最小可重现示例。顺便说一句,您认为buff1while 循环之后指向什么?

标签: c string buffer


【解决方案1】:

您的问题没有解决方案。你要求像向量这样的东西,但向量只知道它们的大小,因为它们存储了它。由于您似乎不允许更改函数的签名,因此循环是您唯一的选择。无论如何,这对我来说似乎并没有那么低效。

您的代码确实存在错误,当您计算 buff1 的大小时,您调整了 buff1 指针,以便在您进行复制时不再指向块的开头。您需要在复制之前减去缓冲区的大小。此外,您似乎假设您的两个输入缓冲区大小相同。

这似乎是您代码的更好版本。

char* func(char *buff1, char *buff2, char *outbuff)
{
    int size1 = 0;
    while (*buff1 != '\0')
    {
        size1++;
        buff1++;
    }
    int size2 = 0;
    while (*buff2 != '\0')
    {
        size2++;
        buff2++;
    }
    memcpy(outbuff, buff1 - size1, sizeof(char)*size1);
    memcpy(outbuff + size1, buff2 - size2, sizeof(char)*size2);
    return outbuff; 
}

您可以使用strlen,它与上面的代码做同样的事情,但strlen 也是一个循环。所以使用strlen 的好处并不是避免了循环,而是代码更容易理解。

#include <cstring>

char* func(char *buff1, char *buff2, char *outbuff)
{
    int size1 = strlen(buff1);
    int size2 = strlen(buff2);
    memcpy(outbuff, buff1, sizeof(char)*size1);
    memcpy(outbuff + size1, buff2, sizeof(char)*size2);
    return outbuff; 
}

那么最后你可以使用strcpystrcat,它们也有类似的效果

#include <cstring>

char* func(char *buff1, char *buff2, char *outbuff)
{
    strcpy(outbuff, buff1);
    strcat(outbuff, buff2);
    return outbuff; 
}

这显然完全避免了任何循环和大小计算。但当然它们仍在发生,只是在 strcpystrcat 函数内部。

此最新版本与之前的两个版本之间存在一个差异。带有strcpystrcat 的版本还将终止'\0' 字符复制到outbuff,因此outbuff 将被空终止,就像您假设buff1 abd buff2 一样。这对我来说似乎是一个优势,但你可能不同意。

【讨论】:

  • func() 无法形成 字符串,因为 outbuff 缺少 空字符。然而,也许 OP 想要这样。嗯。
【解决方案2】:

将输入缓冲区的内容复制到输出缓冲区而不重叠。

由于复制是目标,“我发现这是一种非常低效的查找大小的方法。”被误导了。

即使找到大小可以在没有循环的情况下完成,效率也是 O(n),因为副本需要 O(n)。 “非常低效”属于 O() 更差的情况。


而不是将字符串运行两次,一次就足够了,因为缓冲区是不重叠的。

char * func(const char *buff1, const char *buff2, char *outbuff) {
  char *dest = outbuff;
  while(*buff1) {
    *dest++ = *buff1++;
  }
  while(*buff2) {
    *dest++ = *buff2++;
  }

  // more common to append a \0
  *dest = '\0';

  return outbuff; 
}

【讨论】:

    【解决方案3】:

    C 字符串是以空字符结尾的字符数组。如果您的函数处理合法的 C 字符串,那么您应该使用标准字符串库。 例如,strlen(src)strcpy(dst,src) 等。由于有时字符串会违反以0 结尾的属性,因此标准字符串库提供了类似strncpy(dst,src,n) 的函数,其中执行复制直到空终止字符,只要复制的字符数最多为n

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-22
      • 2022-10-07
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多