[英]How to allocate memory using a pointer to pointer in C
我试图免费阅读双指针中的代码段
我想了解以下内容之间的区别。 这两个片段均来自上述网址
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]
指向它们:
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]
,但是与真正的2D数组不同,行在内存中并不相邻,并且每行的长度可能不同。 您通常将其写为
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]
+---+---+ +---+
以下是错误的,编译器应抱怨类型:
int** 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
+-------------+-------------+-------------+
例如,在C中,要获取绘制的内容,可以编写:
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);
^
如果不进行强制转换,则编译器可以接受此明显无效的代码,因为函数malloc
的返回类型为void *
且类型void *
的指针可以分配给任何其他类型的对象的指针。
也就是说,在赋值的右侧,求值表达式的类型为int *
而在赋值的左侧,则为int **
类型的对象,并且没有从int *
类型到int **
类型的隐式转换。 int **
。
此代码段
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.