【问题标题】:Freeing a C pointer after altering its value更改值后释放 C 指针
【发布时间】:2018-03-30 03:38:40
【问题描述】:

我可以释放一个指针,例如:

unsigned char *string1=NULL;
string1=malloc(4096);

在改变它的值之后:

*string1+=2;

free(string1) 可以识别相应的内存块在递增后释放(例如指向字符串的一部分),还是我需要保留原始指针值以用于释放目的?

例如,对于 C 语言中 Visual Basic 6 函数 LTrim 的实现,我需要将 **string 作为参数传递,但最后我将返回 *string+=string_offset_pointer 以开始超出任何空格/制表符。

我认为我在这里更改了指针,所以如果我这样做,我需要保留原始指针的副本以释放它。将非空白内容覆盖到字符串本身可能会更好,然后用 0 终止它,以避免需要额外的指针副本来释放内存:

void LTrim(unsigned char **string)
{
 unsigned long string_length;
 unsigned long string_offset_pointer=0;


 if(*string==NULL)return;

 string_length=strlen(*string);
 if(string_length==0)return;


 while(string_offset_pointer<string_length)
 {
  if(
     *(*string+string_offset_pointer)!=' ' &&
     *(*string+string_offset_pointer)!='\t'
    )
  {
   break;
  }

  string_offset_pointer++;
 }


 *string+=string_offset_pointer;
}

最好让函数用它的子字符串覆盖字符串,但不改变指针的实际值以避免需要它的两个副本:

void LTrim(unsigned char **string)
{
 unsigned long string_length;
 unsigned long string_offset_pointer=0;
 unsigned long string_offset_rebase=0;


 if(*string==NULL)return;

 string_length=strlen(*string);
 if(string_length==0)return;


 //Detect the first leftmost non-blank
 //character:
 ///
  while(string_offset_pointer<string_length)
  {
   if(
      *(*string+string_offset_pointer)!=' ' &&
      *(*string+string_offset_pointer)!='\t'
     )
   {
    break;
   }

   string_offset_pointer++;
  }



 //Copy the non-blank spaces over the
 //originally blank spaces at the beginning
 //of the string, from the first non-blank
 //character up to the string length:
 ///
  while(string_offset_pointer<string_length)
  {
   *(*string+string_offset_rebase)=
   *(*string+string_offset_pointer);

   string_offset_rebase++;
   string_offset_pointer++;
  }



 //Terminate the newly-copied substring
 //with a null byte for an ASCIIZ string.
 //If the string was fully blank we will
 //just get an empty string:
 ///
  *(*string+string_offset_rebase)=0;


 //Free the now unused part of the
 //string. It assumes that realloc()
 //will keep the current contents of our
 //memory buffers and will just truncate them,
 //like in this case where we are requesting
 //to shrink the buffer:
 ///
  realloc(*string,strlen(*string)+1);
}

【问题讨论】:

  • 你需要保留原来的指针值。
  • 您在示例中没有更改 string1 的值

标签: c pointers memory-leaks


【解决方案1】:

因为你真的在做

unsigned char *string1=NULL;
string1=malloc(4096);
*string1+=2;
free(string1);

free(string1) 正在传递malloc() 调用的结果。

如果string1[0] 未初始化,则*string1 += 2 将——不管free() 的调用——具有未定义的行为。 (即,如果在上面的第二行和第三行之间有一些初始化 string1[0] 的操作,则该行为是完全明确的)。

如果从*string1 += 2 中删除星号以形成语句string1 += 2,则free() 的调用将具有未定义的行为。必须将 malloc()(或 calloc()realloc())返回的值传递给 free(),而该值尚未被释放。

【讨论】:

    【解决方案2】:

    传递给free() 的值必须是malloc()calloc()realloc() 返回的指针。任何其他值都会导致未定义的行为。

    所以如果你修改它,你必须保存原始指针。在您的代码中,您实际上并没有修改指针,您只是增加了它指向的位置的内容,所以您没有这个问题。

    您可能会问,为什么以这种方式指定语言?它允许非常有效的实现。一种常见的设计是将大小分配存储在数据之前的内存位置。因此free() 的实现只是读取该地址之前的内存以确定要回收多少。如果你给出其他地址,它无法知道这是在分配的中间,它需要扫描回到开头才能找到信息。

    更复杂的设计会保留所有分配的列表,然后确定地址指向哪一个。但这会使用更多的内存并且效率会低得多,因为它必须搜索包含的分配。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-06
      • 1970-01-01
      • 1970-01-01
      • 2015-03-08
      • 2014-06-22
      • 1970-01-01
      • 2011-10-28
      • 1970-01-01
      相关资源
      最近更新 更多