如何解除分配2d数组?

时间:2014-09-24 04:11:19

标签: c arrays pointers

已经有很多东西了。他们似乎都暗示你每次调用malloc时都需要做的就是免费调用,并且可能会释放指针的指针"最后 - 所以你不会在它被释放后最终引用该内存

例如,如果我有

int** myPtr

然后我只需要

free(myPtr[j])

为每个j,最后释放指针指针

free(myPtr)

冷却。我在我的程序中已经完成了几次,它看起来工作得很好 - 除了一个案例。我试图弄清楚这种情况有什么不同,我能够在最小程序中复制症状。

#include "stdafx.h"
#include <stdlib.h>

signed char** getPtr()
{
    unsigned char n = 10;
    unsigned char k = 2;

    signed char** myPtr = (signed char**)malloc(n*sizeof(signed char));
    if (myPtr == NULL) {return NULL;}

    for (unsigned char i = 0; i < n; i++)
    {
        myPtr[i] = (signed char*)malloc(k*sizeof(signed char)); 
        if (myPtr[i] == NULL) {return NULL;}
    }

    for (unsigned char j = 0; j < n; j++)
    {
        for (unsigned char k = 0; k <= 1; k++)
        {
            myPtr[j][k] = 42; 
        }
    }

    return myPtr; 

}

int _tmain(int argc, _TCHAR* argv[])
{
    signed char** potato = getPtr();
    if (potato != NULL)
    {
        for (unsigned char j = 0; j < 10; j++)
        {
            free(potato[j]);
        }
        free(potato); 
    }
    return 0;
}

6 个答案:

答案 0 :(得分:11)

您的立即问题如下:

signed char** myPtr = (signed char**)malloc(n*sizeof(signed char));

这是错误的,因为它为n 字符分配了足够的空间。相反,它应该是:

signed char** myPtr = (signed char**)malloc(n*sizeof(signed char*));
//                                                              ^
//                                                      char POINTER

char的大小通常小于指针的大小,但即使不是,也应该使用正确的类型。事实上,我倾向于选择以下形式,以便我不必重复这种形式(重复有可能在将来改变一种,忘记另一种):

signed char** myPtr = (signed char**) malloc (n * sizeof (*myPtr));

除此之外,你应该考虑你实际编码的语言。虽然C和C ++有很多基本的东西,但它们绝不是同一种语言,你编写代码的方式取决于你所针对的是什么。

让我们首先介绍C.在该语言中,您不应该从malloc转换返回值,因为它可以隐藏某些调试的微妙错误。放弃演员会给你:

signed char **myPtr = malloc (n * sizeof (*myPtr));

此外,由于sizeof (char)(裸,有符号和无符号)总是一,因此每当您看到自己乘以时,就更容易丢弃乘法。将其与之前的指南相结合,您可以转向:

myPtr[i] = (signed char*)malloc(k*sizeof(signed char));

更具可读性:

myPtr[i] = malloc (k);

现在,如果您正在编写C ++代码,还需要考虑其他事项。

在C ++中,使用该语言的newdelete方面而不是像mallocfree这样的传统C语言更为可接受。您已经提到的指南(确保每个delete都有new)仍然有效,但确保您在释放数组时使用delete[]会增加复杂性 of items。

这并不是说mallocfree不起作用;它们仍然是C ++语言规范的重要组成部分。只是C ++的处理方式可以更加强大,因为它可以在一次命中中分配初始化对象,并在内存不足时引发异常,这意味着你没有用NULL检查来加密您的代码。

此外,C ++在其标准库中提供了许多集合,这些集合使处理事务组比使用原始数组容易得多。其中一个是vector,基本上是一个可调整大小的数组,您应该考虑在以前使用过数组的情况下使用它。

您展示的代码将更容易实现为字符串向量(C ++字符串,而不是那些微不足道的C字符串)。而且,实际上,我会考虑更进一步,实际上将整个数据结构封装到自己的类中,隐藏它完全使用向量的事实。

如果你这样做,并提供你需要的所有setter / getter方法,你可以稍后替换整个底层数据结构而不会影响使用它的代码。

答案 1 :(得分:5)

您没有为指针指针分配足够的空间。 这样:

signed char** myPtr = (signed char**)malloc(n*sizeof(signed char));

应该是:

signed char** myPtr = malloc(n*sizeof(signed char*));

如果malloc失败,你也会泄漏内存:

for (unsigned char i = 0; i < n; i++)
{
    myPtr[i] = (signed char*)malloc(k*sizeof(signed char)); 
    if (myPtr[i] == NULL) {return NULL;}
}

我有点假设您希望此代码的C版本不能完全移植到C ++。可能有更合适的方法在C ++中完成你真正想要做的事情。

答案 2 :(得分:4)

您需要为n的{​​{1}} 指针分配空间,而不是n signed char

signed char

答案 3 :(得分:3)

您应该使用:

signed char** myPtr = (signed char**)malloc(n*sizeof(signed char*));
                                                                ^^ The missing *

而不是

signed char** myPtr = (signed char**)malloc(n*sizeof(signed char));

否则,您没有为指针分配足够的内存。

当然,您不应该转换malloc的返回值。它已知会引起问题。有关详细信息,请参阅Specifically, what's dangerous about casting the result of malloc?

使用:

signed char** myPtr = malloc(n*sizeof(signed char*));

答案 4 :(得分:1)

getPtr你:

// 1 byte
malloc n*sizeof(signed char)

但是您存储了一个指向已签名字符的指针,该字符为32或64位,4或8字节。

您可以使用以下方法修复它:

signed char*  zz;
signed char** myPtr = (unsigned char)malloc(n*sizeof(zz));

答案 5 :(得分:1)

最简单的方法是使用真正的2D数组,而不仅仅是指向数组的指针数组。您可以像这样分配2D数组:

signed char (*myPtr)[k] = malloc(n*sizeof(*myPtr));

通过此分配,您不需要循环到malloc()行数组。您可以直接使用2D数组:

for (unsigned char j = 0; j < n; j++)
{
    for (unsigned char i = 0; i < k; i++)
    {
        myPtr[j][i] = 42; 
    }
}

请注意,即使内存布局有点不同,访问数组元素的方式也没有变化。但是,由于您在一个大块中分配了内存,因此您还可以在一次free()调用中解除分配:

free(myPtr);

学习C指向数组语法的指针确实是值得的。