【问题标题】:char*/string concatenation without copying?char * / string连接而不复制?
【发布时间】:2015-12-14 16:26:45
【问题描述】:

我想在 C 或 C++ 中连接 2 个字符串,而不需要新的内存分配和复制。有可能吗?

可能的 C 代码:

char* str1 = (char*)malloc(100);
char* str2 = (char*)malloc(50);
char* str3 = /* some code that concatenates these 2 strings
                without copying to occupy a continuous memory region */

然后,当我不再需要它们时,我就会这样做:

free(str1);
free(str2);

或者如果可能的话,我想在 C++ 中实现同样的效果,使用 std::stringchar*,但使用 newdelete(可能在str3)。

关于字符串连接的问题有很多,但我还没有找到相同的问题。

【问题讨论】:

  • 不。不可能。
  • 翻转你的逻辑,分配一个 150 长度的 char 数组,然后将子字符串分配到 0 和 101 的位置(我知道这对于 c++ 是可能的,我不太了解 C)跨度>
  • 没有语言 C/C++。选一个!每个问题一个主题!
  • 您必须创建自己的字符串数据结构来存储指向字符串片段的指针。例如,您可以有一个指向字符串的向量或指针数组。
  • @Olaf:我没有看到任何教程请求。只是对字符串的所有元素缺乏了解。

标签: c++ c string


【解决方案1】:

不,不可能

在 C 中,malloc 操作返回彼此没有关系的内存块。但是在 C 中,字符串必须是一个连续的字节数组。所以没有复制就无法扩展str1,更不用说连接了。

对于 C++,可能对绳索感兴趣:See this answer

绳索被分配在不必连续的块中。这支持 O(1) 连接。但是,访问器使其显示为单个字节串。我敢肯定,将绳索转换回 std::string 或 C 风格的字符串将需要一个副本,但这可能是最接近你想要的。

另外,担心复制一些字符串的成本可能是一种过早的优化。除非您要移动 大量 数据,否则这无关紧要

【讨论】:

  • OP 询问连接字符串而不复制到连续内存区域。这在任何语言中都是不可能的。
  • @Olaf - 你读过我的回答吗:我说“不,不可能”,这听起来像是对我的回答?不要粗鲁。
  • 其实可能的。如果您编写一个行为类似于字符串的新类,但实际上在内部存储了对多个块的引用。原来的 SGI STL 有一个类叫 rope 像这样。
  • 在某些情况下,在某些系统上是可能的。它需要精确的数据放置、物理交换非易失性存储芯片和/或更改地址解码。
  • 我已经删除了 DV。解释完绳子,我就可以忍受了。
【解决方案2】:

可以通过编写自己的字符串数据结构来进行文本连接。 C++ 比 C 更容易。

struct My_String
{
  std::vector<char *> text_fragments;
};

您必须基于此数据结构实现所有文本操作和搜索算法。 C 库中的任何内容都不能应用于My_String 结构。 C++ 中的 std::string 将不兼容。

其中一个问题是如何处理文本修改。如果其中一个文本片段是常量文字(无法修改),则需要先复制它,然后才能对其进行修改。但是复制是违反要求的。 :-(

【讨论】:

    【解决方案3】:

    C 中的“字符串”是一个字符数组,末尾有一个空字符。数组是“一种数据结构,可让您在内存中连续存储一个或多个元素”。 GNU C reference

    如果不复制其中一个,则无法连接不在连续内存块中的两个数组。但是,您可以在不分配新内存的情况下执行此操作。例如

    char* str1 = malloc(100);  // size 100 bytes, uninitialised
    str1[0] = '\0';            // string length 0, size of str1 100
    strcat(str1, "a");         // string length 1, size of str1 still 100
    strcat(str1, "b");         // string length 2, size of str1 still 100
    

    如果您想检索 2 个字符串的字符,就好像它们是一个而不复制或重新分配一样。这是一个示例函数(简单示例,不要在生产代码中使用

    char* str1 = (char*)malloc(100);
    char* str2 = (char*)malloc(50);
    
    char get_char(int i) {
        if (i > 0 && i < 100) {
            return str1[i];
        }
        if (i >= 100 && i < 150) {
            return str2[i-100];
        }
        return 0;
    }
    

    但在这种情况下,您无法使用 char* str3 来执行指针运算并访问所有 150 个字符。

    【讨论】:

      【解决方案4】:

      标签 C 和 C++ 是矛盾的。在 C 语言中,我建议探索realloc。您可以按照以下几行编写代码:

      char* str = malloc(50);
      str = realloc(ptr, 55);
      

      如果幸运的话,realloc 调用不会重新分配新内存,而只是“扩展”已经分配的段,但不能保证这一点。这样,您至少可以避免重新分配字符串。您仍然需要将第二个字符串的内容复制到 neweley 分配的内存中。

      【讨论】:

      • 这是评论,但不是答案
      • @Olaf,怎么会这样?你想在答案中看到什么?
      • 天哪,有 7 位用户同意 Olaf。我的回答有什么问题???如果反对者愿意解释答案有什么问题,那将是非常有益的。帮助大家。
      • @SergeyA 我不明白这如何回答如何在不复制的情况下连接两个字符串的问题。
      • Realloc 无论如何都不能解决问题。如果您有两个字符串,并且重新分配第一个字符串以便它有更多空间,您仍然必须将第二个字符串复制到该额外空间中。即使我遗漏了一些东西,至少还不清楚它是否回答了这个问题,在目前的状态下,它只是提供了一个有用的仅供参考,可能有助于真正的解决方案。这就是为什么你被否决的原因我猜(不是我)。
      猜你喜欢
      • 2010-09-26
      • 1970-01-01
      • 2011-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-13
      相关资源
      最近更新 更多