微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

用calloc分配一个指针,然后用malloc =内存泄漏动态分配每个单元?

如何解决用calloc分配一个指针,然后用malloc =内存泄漏动态分配每个单元?

在最近的考试问题中,我获得了带有以下选项的代码

char **mptr,*pt1;
int i;
mptr = calloc(10,sizeof(char*));
for (i=0; i<10; i++)
{
    mptr[i] = ( char *)malloc(10);
}   

以下哪些解除分配策略会导致内存泄漏?

A。 free(mptr);

B。 for(i = 0; i < 10; i++): { free(mptr[i]); }

C。全部

答案是C。但是在我看来,应用free(mptr);可以解决内存泄漏,B也是如此,尽管我不太确定,但是有人可以解释一下为什么所有人都会这样做吗?导致内存泄漏? 我猜想C选项期望每个操作(A或B)是分开应用的。

P.S。 我看不到这段代码的重点,如果您已经用calloc分配了内存(并对其进行了初始化),为什么还要花一个循环分配每个单元呢?我不相信吗?

解决方法

以下哪些解除分配策略会导致内存泄漏?

在我的专家看来,正确的答案必须是选项A,因为它会释放mptr,导致mptr[i]指针不可访问,因此会导致内存泄漏。假定其他方式完全无法访问内存,则以后无法释放它们。

选项B本身不会导致内存泄漏 ,在释放mptr指针之后,mptr[i]仍然可以访问。您可以重用它,也可以稍后再分配它。只有当您失去对mptr所指向的内存的访问权限时,才会发生内存泄漏。

我认为这个问题的格式有些错误,如果问题是“您将使用哪个选项来正确地释放所有内存?” ,那么,选项C是正确。

我确实同意取消所有内存的正确策略B + A,尽管首先是A会导致立即的内存泄漏,而{{ 1}}首先将允许以后B的重新分配,只要对它所指向的内存的访问没有丢失。

我看不到这段代码的重点,如果您已经用calloc分配了内存(并对其进行了初始化),为什么还要花一个循环分配每个单元呢?我不相信吗?

分配正确。

mptr

Check this thread了解更多信息。

,

让我们把它画出来

      char **        char *                 char
      +---+          +---+                  +---+---+     +---+
mptr: |   | -------->|   | mptr[0] -------->|   |   | ... |   |
      +---+          +---+                  +---+---+     +---+
                     |   | mptr[1] ------+  
                     +---+               |  +---+---+     +---+
                      ...                +->|   |   | ... |   |
                     +---+                  +---+---+     +---+
                     |   | mptr[9] ----+
                     +---+             |    +---+---+     +---+
                                       +--->|   |   | ... |   |
                                            +---+---+     +---+

如果您所做的一切都是释放mptr所指向的内存,那么您将得出以下结论:

      char **                               char
      +---+                                 +---+---+     +---+
mptr: |   |                                 |   |   | ... |   |
      +---+                                 +---+---+     +---+
                       
                                            +---+---+     +---+
                                            |   |   | ... |   |
                                            +---+---+     +---+
                      
                                            +---+---+     +---+
                                            |   |   | ... |   |
                                            +---+---+     +---+

释放每个mptr[i]的分配。这些都是单独的分配,在释放mptr之前,必须 分别释放每个分配。 free不会检查正在释放的内存的内容,以确定是否有任何嵌套的分配也需要释放。正确的程序是写

for ( int i = 0; i < 10; i++ )
  free( mptr[i] );
free( mptr );

如果每个mptr[i]的所有活动都是免费的,而mptr却没有,那么您会发现:

      char **        char *                 
      +---+          +---+                  
mptr: |   | -------->|   | mptr[0] 
      +---+          +---+                  
                     |   | mptr[1]
                     +---+            
                      ...   
                     +---+ 
                     |   | mptr[9] 
                     +---+             

您仍然拥有最初分配的指针数组。现在,这还不是内存泄漏 -仅当您丢失对mptr的跟踪时,它才变为内存泄漏。

因此,这些是C语言中的内存管理规则:

  • 每个malloccallocrealloc呼叫最终都必须具有相应的free
  • 进行嵌套分配时,请始终按照分配的相反顺序进行分配(即,在分配ptr[i]之前先分配每个ptr);
  • free 必须的参数必须是从malloccallocrealloc调用返回的指针。

P.S。我看不到这段代码的重点,如果您已经用calloc分配了内存(并对其进行了初始化),为什么还要花一个循环分配每个单元呢?我不相信吗?

这是一个“锯齿状”数组的示例,其中每个“行”的长度可以不同(常规2D数组无法做到)。如果要存储(例如)所有不同长度的单词列表,这会很方便:

char **        char *        char
+---+          +---+         +---+---+---+---+
|   | -------->|   |-------->|'f'|'o'|'o'| 0 |
+---+          +---+         +---+---+---+---+
               |   | -----+  
               +---+      |  +---+---+---+---+---+---+---+
               |   | ---+ +->|'b'|'l'|'u'|'r'|'g'|'a'| 0 |
               +---+    |    +---+---+---+---+---+---+---+
                ...     |
                        |    +---+---+---+---+---+---+
                        +--->|'h'|'e'|'l'|'l'|'o'| 0 |
                             +---+---+---+---+---+---+

如有必要,您可以轻松调整每个“行”的大小而不会影响其他任何行,并且可以轻松添加更多“行”。当您为 索引时,它看起来像是2D数组-您可以像其他任何2D数组一样使用mptr[i][j]访问单个元素-但“行”在内存中并不连续。

将此与“真实的” 2D数组进行比较,其中所有行的大小均相同并且连续布置:

+---+---+---+---+---+---+---+
|'f'|'o'|'o'| 0 | ? | ? | ? |
+---+---+---+---+---+---+---+
|'b'|'l'|'u'|'r'|'g'|'a'| 0 |
+---+---+---+---+---+---+---+
|'h'|'e'|'l'|'l'|'o'| 0 | ? |
+---+---+---+---+---+---+---+

主要缺点是浪费了一些空间。必须将数组的大小调整为要存储的最长单词。如果您有一个包含100个字符串的表,其中一个字符串的长度为100个字符,其余的为10个字符,那么您将浪费很多空间。您不能有比其他行更长的行。

优点是行是连续的,因此沿着数组“遍历”更加容易。

请注意,您也可以动态分配常规2D数组:

char (*ptr)[10] = calloc( 10,sizeof *ptr );

这会为char 的10x10阵列分配足够的空间 ,您可以像其他任何2D数组一样将其编入索引:

strcpy( ptr[0],"foo" );
ptr[0][0] = 'F';

由于这是一次分配,因此您只需要一次取消分配:

free( ptr );
,

free(mptr);仅释放分配给指针的内存,而不释放指针指向的内存。

如果在释放指针所指向的内存之前free()为指针分配了内存,那么您将不再有指向要指向的内存的引用,因此会发生内存泄漏。


另一方面,

for(i = 0; i < 10; i++): { free(mptr[i]); }仅释放指向的内存,而没有释放指针。根据您对它的严格程度的考虑,您也可以将其视为内存泄漏,因为指针的内存未释放。

因此,根据观点和个人观点,A。或C.是正确的。


我看不到这段代码的重点,如果您已经用calloc分配了内存(并对其进行了初始化),为什么还要为每个单元分配一个循环呢?

使用

mptr = calloc(10,sizeof(char*));

您为指针mptr所指向的 pointers 本身分配了内存。

但是指针需要指向您可以使用指针访问的数据存储器。指针本身不能存储指向指向的内存地址以外的任何其他数据。

因此,您需要通过for循环内的每次迭代为每个指针分配指向的内存。

指针始终需要指向一个位置才能正确使用它作为指针(异常:空指针)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。