【问题标题】:C++ char array[] memory leak [duplicate]C ++ char数组[]内存泄漏[重复]
【发布时间】:2020-08-18 13:01:26
【问题描述】:

我创建了 char arr[] 并分配给它字符串文字

char arr[] = "some string";                  // arr occupies 12 chars in memory
std::cout << std::strlen(arr)  << std::endl; // lenght is 11 chars + 1 null-terminator
                                             //arr[11] is '\0'

接下来我将空终止符放入 6 个元素中

arr[5] = '\0';
std::cout << std::strlen(arr) << std::endl; // lenght is 5 chars  + 1 null-terminator
  1. 是内存泄漏吗?
  2. 编译器如何知道它必须在第一个 '\0' 之后释放内存? (什么时候删除变量 arr)
  3. 是否可以更改此 arr 变量的长度并通知编译器它应该释放多少 删除变量?

【问题讨论】:

  • 这里没有分配内存,因此不可能有泄漏。
  • @Mansoor 是的。 arr 为 12 个字节。
  • 是否可以更改此 arr 变量的长度并通知编译器在删除变量时应该释放多少? c++ 中的数组是在编译时固定大小。
  • 内存是如何被跟踪和释放的,这一切都在幕后。它没有定义实现必须如何释放内存,只是它必须(在必须的情况下)。如果char arr[]; 具有自动存储功能(例如,是一个局部变量),那么它可能会在堆栈指针更改时被“释放”,并在下次堆栈增长超过数组原来的位置时重新使用。
  • 这能回答你的问题吗? c++ string allocation

标签: c++ memory


【解决方案1】:

在这段代码中:

char arr[] = "some string";

变量arr 是一个具有固定大小的静态 数组。这里没有动态内存分配,因此无需担心内存泄漏。无论您在arr 中写入什么内容,编译器都会处理内存。

【讨论】:

    【解决方案2】:
    1. 是内存泄漏吗?

    没有。

    1. 编译器如何知道它必须在第一个 '\0' 之后释放内存? (什么时候删除变量 arr)

    变量为 12 个字符。和写一样:

    char arr[12] = "some string";
    

    所以它总是会释放 12 个字符。变量一个12个字符的数组;第 6 个字符恰好是 '\0' 的事实完全无关紧要。

    顺便说一句,一旦你将第 6 个字符设置为 '\0',你仍然可以使用所有 12 个字符,因为它仍然是一个 12 个字符的数组。即使是'\0'之后的那些。但你不能在其中存储 13 个字符。

    1. 是否可以更改此 arr 变量的长度并通知编译器在删除变量时应该释放多少?

    没有。无法更改任何变量的大小。

    【讨论】:

    • 值得一提的是该变量具有自动持续时间
    【解决方案3】:

    为了完整性。

    在分配的内存中也没有内存泄漏,如下所示:

    char* arr = (char*) malloc(12);
    strcpy(arr, "some string");
    arr[6] = '\0';
    free(arr);
    

    内存管理通过分配的内存 (12),而不是通过底层使用(以 nul 终止的字符 *)。 (C风格,C++也一样)

    【讨论】:

    • 免费(arr);
    • @vova 是的。 free 不关心分配内存的内容。
    • 您可以将 malloc void* 指针转换为任何东西。 C++ new char[12] 是另一个但实际上类似的问题,需要调用delete[]
    【解决方案4】:

    看起来你把它弄反了。 C++ 中的数组大小不能更改,句号。由于这个事实,并且因为如果您将数组作为指针传递,您会丢失该数组的实际大小的信息 agreement 是为 C 样式字符串创建的 - 0 字节又名 \0 又名空终止符处理作为字符串的动态结尾。协议意味着使用 C 样式字符串的函数将其视为字符串终止。这允许您对不同长度的字符串使用固定大小的数组,并且只将一个没有实际内存大小的指针传递给要从中读取的函数(例如打印到屏幕)。请注意,当您将 char 数组传递给向其中写入数据的函数时,您通常需要告诉它实际数组大小是多少,这样该函数就不会越界访问内存,因为这些函数会忽略空终止符如果它已经存在。

    就是这样,这个协议发生在阵列管理的不同层上。因此,从语言的角度来看,您放入该数组中的任何数据都不会影响其大小,对于 C++ 编译器,您创建了 fixed size 数组,您将一些数据放入其中,当它的生命周期结束时,编译器会销毁它作为整个固定大小的数组。它不关心您是否将零字节放在那里。

    【讨论】:

      【解决方案5】:

      当程序员使用运算符 new 分配内存并且未使用运算符 deletedelete [] 删除时,就会发生内存泄漏。

      在此声明中

      char arr[] = "some string"; 
      

      它是编译器(或系统)为字符数组 arr 分配的内存,具有自动存储持续时间或静态存储持续时间。因此编译器(或系统)负责释放分配的内存。编译器(或系统)知道分配的内存地址。

      使用此语句

      arr[5] = '\0';
      

      您没有重新分配数组。您只是更准确地更改了它的内容,只更改了一个字节。

      编译器如何知道它必须在第一个'\0'之后释放内存? (什么时候删除变量arr)

      因为编译器(或系统)知道数组类型的对象是如何声明的。

      为对象分配了 12 个字节。

      char arr[] = "some string"; 
      

      是否可以更改此 arr 变量的长度并通知 编译器删除变量时应该释放多少?

      我认为您的意思是对象的大小。不,您不能更改对象的大小,因为为对象分配内存的不是您。

      如果您使用运算符new 来分配对象,您可以重新分配对象,例如

      char *arr = new char[12];
      
      std::strcpy( arr, "some string" );
      
      //...
      
      char *tmp = new char[20];
      
      strcpy( tmp, "another " );
      strcat( tmp, arr );
      
      delete [] arr;
      arr = tmp;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-10-09
        • 1970-01-01
        • 1970-01-01
        • 2014-11-13
        • 2017-02-19
        • 1970-01-01
        • 2015-07-22
        • 2013-06-15
        相关资源
        最近更新 更多