Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C中使用指针分配内存_C_Pointers_Malloc - Fatal编程技术网

如何在C中使用指针分配内存

如何在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*类型的变量,它可能包含某些内存的地址,这

我试图理解中的代码片段

我想了解以下两者之间的区别。这两个代码段都来自上述URL

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