我正在尝试理解以下代码片段:如何释放一个双重指针
我想要理解以下两者之间的区别。这两个片段都来自上述网址。
int** pt;
pt = (int*) malloc(sizeof(int)*10);
并且
*pt = (int*) malloc(sizeof(int)*10);
能否举几个例子并画图加以说明?
我正在尝试理解以下代码片段:如何释放一个双重指针
我想要理解以下两者之间的区别。这两个片段都来自上述网址。
int** pt;
pt = (int*) malloc(sizeof(int)*10);
并且
*pt = (int*) malloc(sizeof(int)*10);
能否举几个例子并画图加以说明?
首先,这段代码有几个问题 - 第一个是将malloc
的结果转换为了错误的类型,并且使用了错误的类型来计算内存大小。修复转换和类型问题后,我们得到:
int **pt;
pt = malloc( sizeof *pt * 10 ); // allocate space for 10 int *
*pt = malloc( sizeof **pt * 10 ); // allocate space for 10 int
执行第一行后,您将拥有以下内容: int ** int *
+---+ +---+
pt: | | --------------->| | pt[0]
+---+ +---+
| | pt[1]
+---+
| | pt[2]
+---+
...
+---+
| | pt[9]
+---+
你已经为10个 int *
对象分配了空间,pt
指向它们中的第一个。下一行:
*pt = malloc( sizeof **pt * 10 ); // allocate space for 10 int
为10个int
对象分配空间,并将pt[0]
设置为指向它们的地址:
分配空间给10个int
对象,并将pt[0]
指向它们的地址:
int ** int * int
+---+ +---+ +---+
pt: | | --------------->| | pt[0] -------->| | pt[0][0]
+---+ +---+ +---+
| | pt[1] | | pt[0][1]
+---+ +---+
| | pt[2] | | pt[0][2]
+---+ +---+
... ...
+---+ +---+
| | pt[9] | | pt[0][9]
+---+ +---+
这展示了一种分配“不规则”数组的方法;你仍然可以像访问真正的二维数组一样访问它,即pt[i][j]
,但与真正的二维数组不同的是,行在内存中不相邻,并且每行可能具有不同的长度。通常会将其写为:
pt = malloc( sizeof *pt * ROWS );
if ( pt )
{
for ( size_t r = 0; r < ROWS; r++ )
{
pt[r] = malloc( sizeof *pt[r] * COLS );
}
}
完成所有这些步骤后,您将拥有如下内容:
int ** int * int
+---+ +---+ +---+---+ +---+
pt: | | ---------> | | pt[0] --------> | | | ... | | pt[0][0] - pt[0][COLS-1]
+---+ +---+ +---+---+ +---+
| | pt[1] ------+
+---+ | +---+---+ +---+
| | pt[2] ---+ +-> | | | ... | | pt[1][0] - pt[1][COLS-1]
+---+ | +---+---+ +---+
... |
| +---+---+ +---+
+----> | | | ... | | pt[2][0] - pt[2][COLS-1]
+---+---+ +---+
sizeof *pt
而不是sizeof(int)
可以消除特定问题。无论T
如何,T *p = malloc(sizeof *p * N);
始终会做正确的事情。 - John Bodep
,我将使用sizeof *p
,而不是sizeof some_arbitrary_type_that_isn't_the_same_type_as_*p
。 - John Bodeint** pt;
pt = (int*) malloc(sizeof(int)*10);
另一个错误的原因是这里的pt
实际上没有指向任何可用的内容:
int** pt;
*pt = (int*) malloc(sizeof(int)*10);
T
的指针是一种类型为T *
的变量,它可能包含某些内存的地址,该内存可能包含T
类型的元素。+------+
| | pointer to T
+------+
|
v
+-------------+-------------+-------------+
| | | | elements of type T
+-------------+-------------+-------------+
int *pi;
pi = malloc(sizeof(int)*3);
T
,那么图表可能如下所示:+------+
| | pointer to pointer to T
+------+
|
v
+------+------+------+
| | | | pointers to T
+------+------+------+
| | | +-------------+-------------+-------------+
| | +---->| | | | elements of type T
| | +-------------+-------------+-------------+
| | +-------------+-------------+
| +---->| | | elements of type T
| +-------------+-------------+
|
v
+-------------+-------------+-------------+-------------+
| | | | | elements of type T
+-------------+-------------+-------------+-------------+
代码可以是这样的:
int **ppi;
ppi = malloc(sizeof(int *)*3);
ppi[0] = malloc(sizeof(int)*3);
ppi[1] = malloc(sizeof(int)*2);
ppi[2] = malloc(sizeof(int)*4);
malloc
可能会失败,返回值应该与失败进行测试。int** pt;
pt = (int*) malloc(sizeof(int)*10);
error: assignment from incompatible pointer type [-Werror=incompatible-pointer-types]
pt = (int*) malloc(sizeof(int)*10);
^
int** pt;
*pt = (int*) malloc(sizeof(int)*10);
由于另一个原因无效。指针pt
未使用有效对象的地址进行初始化。如果指针具有自动存储期限,则其值可能不确定;如果指针具有静态存储期限,则其值为NULL。在任何情况下,对其进行解引用将导致未定义行为。
因此,正确的写法应该是
int* pt;
^^^^^^^
pt = (int*) malloc(sizeof(int)*10);
int** pt;
//...
*pt = (int*) malloc(sizeof(int)*10);
int *pt;
如果您想在函数中初始化指针,则需要通过引用将指针传递给函数。否则,函数将处理指针的副本,在这种情况下,原始指针将不会在函数中被分配。
因此,相应的代码片段可以如示例程序所示。
#include <stdlib.h>
#include <stdio.h>
size_t f( int **pt )
{
const size_t N = 10;
*pt = (int*) malloc( sizeof( int ) * N );
if ( *pt )
{
int value = 0;
for ( size_t i = 0; i < N; i++ ) ( *pt )[i] = value++;
}
return *pt == NULL ? 0 : N;
}
int main( void )
{
int *pt;
size_t n = f( &pt );
if ( n )
{
for ( size_t i = 0; i < n; i++ ) printf( "%d ", pt[i] );
putchar( '\n' );
}
free( pt );
}
程序输出为
0 1 2 3 4 5 6 7 8 9