如何在C中使用指针分配内存
我试图理解中的代码片段 及 我想了解以下两者之间的区别。这两个代码段都来自上述URL如何在C中使用指针分配内存,c,pointers,malloc,C,Pointers,Malloc,我试图理解中的代码片段 及 我想了解以下两者之间的区别。这两个代码段都来自上述URL int** pt; pt = (int*) malloc(sizeof(int)*10); 及 你能用一些例子和绘图来详细说明一下吗?以下是错误的,编译器应该抱怨类型: int** pt; pt = (int*) malloc(sizeof(int)*10); 这也是错误的,还有另一个原因(此处pt实际上没有指向任何可用的内容): 指向T的指针是T*类型的变量,它可能包含某些内存的地址,这
int** pt;
pt = (int*) malloc(sizeof(int)*10);
及
你能用一些例子和绘图来详细说明一下吗?以下是错误的,编译器应该抱怨类型:
int** pt;
pt = (int*) malloc(sizeof(int)*10);
这也是错误的,还有另一个原因(此处pt
实际上没有指向任何可用的内容):
指向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
可能会失败,返回值应该针对失败进行测试。首先,代码片段不好有几个原因-第一个原因是将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** pt;
pt = (int*) malloc(sizeof(int)*10);
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** pt;
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 );
}
请不要将指向指针的指针称为“双指针”。后者听起来太像一个双指针,这是一个完全不同的动物。不要在C++中使用Maloc。@ PeeBekKead。谢谢你的帮助suggestion@manni66. 我使用的不是C + C++。我正在寻找答案可能的结果转换副本是一个非常好的主意,因为它允许编译器为这个语句发出消息pt=(int*)malloc(sizeof(int)*10)@弗拉德夫罗姆莫斯科:使用
sizeof*pt
而不是sizeof(int)
可以消除这个问题<代码>T*p=malloc(sizeof*p*N)无论T
,code>始终会做正确的事情。您确定吗?考虑例如char *p= Maloc(sieof(结构A));char*p=malloc(sizeof*p)@弗拉德夫罗姆莫斯科:我不知道你想表达什么意思——如果我的目标是p
,我将使用sizeof*p
,而不是sizeof一些武断的类型,它们与
的类型不同。这并不总是正确的。例如,您需要分配一个用于复制结构的字符缓冲区,或者您需要分配一个可以容纳二维数组的一维数组,等等。您不能将指针从main()传递到f()吗。如果不是,为什么不呢?@user2979872事实上,我在回答中描述了为什么不可能。你能详细说明什么是不清楚的吗?不清楚的是f(pt)和f(&pt)之间的区别。当您将pt声明为int*pt时,我想知道pt和&pt之间的区别是什么。如果我理解正确,&pt表示pt的地址,pt指向pointee的地址(仅当像pt=&a这样赋值时,其中a声明为int a=5)。否则,pt指向无效地址。如果我是,请纠正我wrong@user2979872pt和&pt是不同的类型,这写在答案中。因此,编译器将发出错误,因为参数的类型与参数的类型不对应。我们将更改函数中的原始pt。因此,我们必须通过引用传递它,否则函数将处理pt的副本,并且副本(而不是原始pt)将在函数中更改。@user2979872对不起,我不理解您在注释中的意思。表达式&pt产生变量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