变长字符串的内存管理

方法1:静态内存

这里有一个方法来实现帮助函数:
  1. const char *
  2. get_string()
  3. {
  4.         static char buf[10000]; /* Big enough */
  5.         /* Read string inot buf... */
  6.         return buf;
  7. }
复制代码

这个方法的好处是比较简单,但是它也有很多严重的缺点。

返回的字符串可能比你期望的要长。无论你指定buf什么样的长度,它仍然可能太小。如果实际的字符串太长,你或者超出数组的范围最终导致代码悲惨的失败,或者必须擅自截断那个字符串。

对于较短的字符串,这个函数因为buf数组的大部分没有用到而浪费了内存。每一次get_string调用覆盖了前一次调用的结果。如果调用者想保留前一次调用的字符串,在再一次调用这个函数之前,他必须把上一次的字符串做一份拷贝。

这个函数不是可重入的。如果多个线程同时调用get_string,一个线程会覆盖另一个线程的结果。

方法2:静态指针指向的动态内存

这是第二种实现get_string函数的方法:
  1. const char *
  2. get_string()
  3. {
  4.         static char * result = 0;
  5.         static size_t rsize = 0;
  6.         static const size_t size_of_block = 512;
  7.         size_t rlen;
  8.         rlen = 0;
  9.         while (data_remains_to_be_read() ) {
  10.                 /* read a block of data... */
  11.                 if ( rsize - rlen < size_of_block ) {
  12.                         rsize += size_of_block;
  13.                         result = realloc(result, rsize);
  14.                 }
  15.                 /* append block of data to result... */
  16.                 rlen += size_of_block;
  17.         }
  18.         return result;
  19. }
复制代码

这个方法使用指向动态内存的一个静态指针,不断地增长缓冲区用来容纳数据。使用动态内存除去了字符串任意长度的限制,当然另一方面它
仍然有前一个方法的问题:每一次调用仍然覆盖前一次调用的结果,函数不是可重入的。这个版本也浪费了相当大数量的内存,因为它永远消
耗最坏情况下的内存数量(它曾经读取的最长字符串的长度)。

方法3:调用者分配的内存

在这个方法中,我们让调用者负责提供容纳字符串的内存。
  1. size_t
  2. get_string(char * result, size_t rsize)
  3. {
  4.         /* read at most rsize bytes into result... */
  5.         return number_of_bytes_read;
  6. }
复制代码

这个就是被UNIX操作系统的read系统调用所采纳的方法。它解决了大部分的问题。包括它是可重入的,不会内存溢出,不会擅自的截断数据。
(潜在的浪费内存的数量在调用者的控制之下。)

弊端在于如果字符串比提供的缓冲区更长,调用者必需保持调用直到所有的数据被读取。(如果我们假定数据源隐含在调用的线程中,那么多
个线程的重复调用是可重入的。)

方法4:返回指针指向的动态内存

在这个方法中,get_string动态的分配一个足够大的缓冲区来容纳结果,并返回一个指向缓冲区的指针。
  1. char *
  2. get_string()
  3. {
  4.         char * result = 0;
  5.         size_t rsize = 0;
  6.         static const size_t size_of_block = 512;
  7.         while (data_remains_to_be_read) {
  8.                 /* read a block of data... */
  9.                 rsize += size_of_block;
  10.                 result = realloc(result, rsize);
  11.                 /* append block of data to result... */
  12.         }
  13.         return result;
  14. }
复制代码

这个几乎和第二个方法一样(它们之间的区别是get_string没有使用静态数据)。它几乎解决了所有的问题:函数是可重入的,对于结果字符
串没有一个隐含的大小限制。对于长字符串并不要求多次的函数调用(但是动态分配增加了一些开销)。

这个方法的主要缺点是它让调用者负责释放分配的内存:
  1. /* ... */
  2. {
  3.         char * result;
  4.         result = get_string();
  5.         /* Use result... */
  6.         free(result);

  7.         /* ... */
  8.         result = get_string();
  9.         /* ... */
  10. }        /* Bad news, forgot to deallocate last result! */
复制代码
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值