【问题标题】:Concatenate Strings in C - `strcpy(s1 += strlen(s1), s2)`在 C 中连接字符串 - `strcpy(s1 += strlen(s1), s2)`
【发布时间】:2019-01-16 22:32:11
【问题描述】:

我正在尝试理解“标准 C 库”中提出的连接字符串的方法。

在讨论了如何连接两个字符串 s1 和 s2 之后。作者提出,对于多个字符串(2个以上),

“...喜欢strcpy(s1 += strlen(s1), s2)这样的形式,这样可以节省对字符串初始部分的重复和不断加长的重新扫描...”(第395页)

我无法理解这段代码 sn-p。我的理解是,他将s1的长度添加到指针中,以便将Null字符的索引传递给strcpy,这样strcpy就不必遍历s1来查找Null字符,而可以开始将s2复制到s1,对吗?

如果我的理解是正确的,那么当strlen代替strcpy时,这如何提高效率?

【问题讨论】:

  • 因为对于多个连接,您不必扫描正在构建的 整个 字符串。缺点是更容易忘记是否有足够的空间来调用固有危险的strcat 或其等效项。
  • strcpy() 在复制前不扫描空终止符。 strcat() 确实如此。作者通过使用strcpy(s1 += strlen(s1), s2) 来避免strcat(s1, s2)。但是,strlen() 扫描空终止符,所以这并没有真正获得任何东西。但是,如果您可以避免strlen(),那么这将变得更加有用
  • @Ry- 这是同一个“问题”的“解决方案”。
  • 请注意,需要注意确保您没有跑过目标缓冲区的末尾——在 C 中总是需要这种注意。显示的代码片段是好方法的核心它(它避免了与 strcat() 重复字符串连接所导致的二次行为 - 请参阅 Shlemiel the Painter;如果您不这样做,Google 知道,请参阅上面的 Joel on Software 链接)。但除非知道使用它的更大背景,否则它不是“安全的”。

标签: c pointers c-strings


【解决方案1】:

是的:s1 += strlen(s1) 会给你一个指向终止 0 的指针,所以 strcpy(..., s2) 将像 strcat() 一样工作 - 将 s2 附加到 s1 (假设 @987654326 中有足够的空间@. 请注意,strcpy() 不会“循环通过 s1 来查找 Null”——它只是在给定的位置写入 strcat 确实找到了 Null。

优化的关键是+=,我们实际上是在更改s1(你最好把原始值复制一份)。所以我们只取最后一个字符串的长度,而不是从第一个字符串开始的长度(这是strcatsolution 所做的)。

【讨论】:

  • "请注意,strcpy() 不会“循环 s1 以查找 Null”" - 是的,但 strlen() 会,所以 strcat(s1, s2) 和 @987654335 @ 在性能方面实际上是相同的。两者都扫描s1 以确定在哪里附加s2
  • @RemyLebeau 是的 - 只是解决问题中 OP 暗示(根据我的阅读)strcpy“寻找空值”的问题
  • @RemyLebeau 但是现在s1 指向(原始)字符串的末尾,而不是它的开头,因此后续调用只需迭代到新连接部分的末尾.它没有达到应有的效率,但它是一种改进。
【解决方案2】:

strcpy(s1 + strlen(s1),s2)确实s1 的重新扫描量限制为在下一轮重复计算给定s2 的额外长度。

但是,IMO,而不是这个技巧,最好只编写一个不需要任何重新扫描的函数:

char *
xstrcat(char *s1,const char *s2)
{

    for (;  *s1 != 0;  ++s1);

    for (;  *s2 != 0;  ++s1, ++s2)
        *s1 = *s2;
    *s1 = 0;

    return s1;
}

void
func(char *s1,const char *s2,const char *s3,const char *s4)
{

    s1 = xstrcat(s1,s2);
    s1 = xstrcat(s1,s3);
    s1 = xstrcat(s1,s4);
}

【讨论】:

  • 这个想法是s1 += strlen(s1) 还保留了strlen 操作(在s1 中)的一些内存,从而降低了后续操作的成本。它并不完美,但确实可以防止遍历量在每个连续的串联中复合。
  • @ChristianGibbons 好的,按照strlen 的概念,[有点] 更好[我已经编辑了我的答案]。但是,这是我第一次看到它(无论是在描述中还是在工作代码中),所以如果它值得复杂,IMO,它将得到更广泛的使用。
猜你喜欢
  • 1970-01-01
  • 2012-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-12
  • 1970-01-01
  • 2021-04-16
相关资源
最近更新 更多