【问题标题】:How to expand a string capacity without using realloc()?如何在不使用 realloc() 的情况下扩展字符串容量?
【发布时间】:2019-12-13 15:27:17
【问题描述】:

我试图想办法在不使用realloc 的情况下扩展字符串容量。例如这段代码的主要区别是什么:

void insert(char *dest, char *src, int pos){

    char *temp = malloc(strlen(dest)+strlen(src)+1);

    /*
    malloc failure handling
    */

    strcpy(temp,dest);
    //rest of code

}

和:

void insert(char *dest, char *src, int pos){

    char *temp =(char*)realloc(dest,strlen(dest)+strlen(src)+1);
    /*
    realloc failure handling
    */

    dest = temp;
    //rest of code

}

或者有什么更好的方法吗?

注意srcdest 都使用malloc 初始化。

【问题讨论】:

  • 可能是一个链表。可能无法使用string.h 操作。
  • 这两个代码或多或少做同样的事情,但无论如何它们都有缺陷,insert 的调用者永远不会看到新指针。在 C 中,变量是按值传递的。实际上realloc 基本上是这样做的:1.分配新的大小。 2. 将旧缓冲区的内容复制到新分配的内存中。 3. 释放旧缓冲区。 realloc有什么问题?我们需要更多的上下文信息。基本上你不能不使用某种形式的动态内存分配来做到这一点。
  • "主要区别" 是第二个 sn-p 不必要地转换了返回 void* 的分配函数的结果! ;)

标签: c string memory-management malloc realloc


【解决方案1】:

实际上,malloc --> memcpy --> free 在概念上就是 realloc 所做的,只是做了一些优化。

由于这个优化,这个问题

这段代码的主要区别是什么

可以这样回答,前者在内存碎片方面可能更快更有效。


如何在不使用 realloc() 的情况下扩展字符串容量?

如果 VLA's* 可用(在C99 之前没有,可能在C11 中,在C++ 中从来没有)并且你知道输入的最大大小这个大小永远不会导致堆栈溢出然后只有然后你可以这样做:

#include <stdio.h>
#include <string.h>

...

  char s1[] = "123";
  char s2[] = "456";
  char s3[] = "789";
  char s[strlen(s1) + strlen(s2) + strlen(s3) + 1];

  strcpy(s, s1);
  strcat(s, s2);
  strcat(s, s3);

  puts(s);

会看到

123456789

总而言之,如果从malloc() 开始玩,那么没有理由不转向它的表亲realloc()

【讨论】:

  • 谢谢。我还假设 strcpy() 在字符串管理方面比 memcpy() 更好,这就是为什么我首先避免使用 realloc
  • VLA 方法是一个真的很 坏主意,我撤回了基于它的初始支持。如所写,它适用于硬编码的字符串,但其中任何一个都是不受控制的输入,这是一个等待发生的堆栈溢出/可释放堆栈冲突错误。正确使用 VLA 非常微妙,很少适用,并且不属于似乎只是学习语言的人的答案。
  • @R.. 我在写这篇文章的时候已经有一种不好的感觉,但是......好吧......只是忽略了它。你说的太对了。需要考虑现在该怎么做,因为它甚至被接受了......
  • @Ashes: "假设 strcpy() 在字符串管理方面比 memcpy() 好,这就是我避免使用 realloc 的原因 错误什么?你避免了 realloc() 究竟是为什么?
  • @alk 主要是为了避免realloc 失败,但我的问题也涉及仅从dest 复制第一个i 字符,所以我打算改用strncpy()。抱歉没有说清楚。
【解决方案2】:

realloc 等价于

void *my_realloc(void *old_p, size_t new_size) {
   void *new_p = malloc(new_size);
   if (!new_p)
      return NULL;

   size_t old_size = ...;
   if (old_size < new_size)
      memcpy(new_p, old_p, old_size);
   else
      memcpy(new_p, old_p, new_size);

   free(old_p);
   return new_p;
}

除了realloc 可能会扩展或缩小现有的内存块。这样可以避免将字节从旧位置复制到新位置。

这意味着realloc 至少和malloc+memcpy+free 一样快,但可能更快。

【讨论】:

  • ... 和 realloc 也可以收缩现有的内存块。
  • @Jabberwocky,确实。已编辑。
【解决方案3】:

主要区别在于一个好的 realloc 实现会进行优化并尽可能跳过副本。 (可以像检查内存中是否有连续的可用空间来扩大分配,但这取决于内存的管理方式)。

如果您不想编写某种内存管理来在运行时处理未定义长度的字符串,那么没有比 realloc 更好的解决方案了。

【讨论】:

    猜你喜欢
    • 2010-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 2011-07-14
    • 2020-09-07
    • 1970-01-01
    • 2018-05-10
    相关资源
    最近更新 更多