【问题标题】:What is the meaning of this pointer to pointer statement in C? [closed]C中这个指向指针语句的指针是什么意思? [关闭]
【发布时间】:2017-10-23 12:31:59
【问题描述】:
int **arr = (int **)malloc(r * sizeof(int *));

我应该如何解释上面的C代码的含义?

【问题讨论】:

  • 问题太宽泛了,但是:int foo; 声明了一个int。 int *foo;声明一个指向int 的指针。 int **foo; 声明了一个指向int* 的指针,即指向int 的指针。
  • 这可能是r指向int的指针数组的动态分配。这些指针可能将被用作构造ints 的穷人的二维(或更多)数组的一部分。没有看到更多代码,我们无法更具体。
  • 将鼠标悬停在“双指针”标签上,看看为什么不应该将其称为“双指针”。

标签: c pointers declaration pointer-to-pointer


【解决方案1】:

对malloc()的调用:

int **arr = (int **)malloc(r * sizeof(int *));

为r 指向int 的指针分配空间,并返回一个指向分配的void *。然后将该指针转换为int ** 并分配给arr,这是一个指向int 的指针。因此arr 指向分配区域的第一个元素,它是指向int 的指针。此类代码可用于创建“锯齿状”数组,其中数组的每一行都是单独分配的;这意味着分配在内存中可能不连续,因此这不是真正的二维数组。请参阅Correctly allocating multi-dimensional arrays 了解更多信息。

不过,以上内容被认为是不好的风格。最重要的是,应尽可能避免使用显式类型作为 sizeof 运算符的参数:

int **arr = (int **)malloc(r * sizeof *arr);

如果arr 的类型在代码生命周期中的某个时间点发生变化,这更不容易出错,并且更易于维护。

另外,there is no need to cast the result of malloc() in C,所以这个演员表是多余的,只会使代码混乱:

int **arr = malloc(r * sizeof *arr);

作为最后的改进,在这种情况下,我更喜欢将 sizeof 表达式放在首位:

int **arr = malloc(sizeof *arr * r);

在上面的特定情况下这是一个无用的变化,但是当有一个额外的乘法时,例如:

int **arr = malloc(sizeof *arr * r * n);

这保证了算术是使用至少与size_t 一样宽的类型执行的,从而降低了整数溢出的风险(signed 整数溢出导致 C 中的未定义行为),并且可能会降低 @987654344 的风险@整数环绕(定义明确,但可能出乎意料或不受欢迎)。

【讨论】:

  • "... 保证使用 size_t 类型执行算术..." 但不保证算术在 size_t 内执行类型,虽然。根据C11/6.3.1.8p1,“...整数转换等级较小的操作数类型转换为等级较大的操作数类型...”.
  • "...消除整数溢出的风险..."。哦。这如何消除整数溢出的风险?如果操作数具有相同的值,则结果将相同。
  • "... 可能会降低无符号整数环绕的风险..." 并非如此。您最好的选择是将r 和n 声明为size_t(无论如何您都应该这样做,对吗?),并且...您听说过“F”模式吗?这是一个热图,显示了我们大多数眼睛在登陆页面的最初几分钟内所关注的位置。您应该尽量将最有用的信息放在靠近页面左侧的位置。
  • @Sebivor -- 已编辑。如果r具有较小的转换等级,则sizeof *arr * r与size_t一起执行,然后如果n具有较小的转换等级,则与size_t执行第二次乘法。如果r 或n 具有更高的转换等级,则生成的类型将是更宽的类型。因为unsigned 类型不会溢出,所以整数溢出被删除。但是,我想更大的signed 类型可能会溢出。这确实是一种降低风险的策略。
  • 你是对的。嘿,我错过了......虽然它很明确,但演员表达式不能是乘法表达式,所以它就像你说的那样从左到右。不过,我坚持我的观点,你不应该在 C 中使用这样的例子。例如,有人告诉过你多少次“fflush(stdin); 为我工作”?可能没有...知道我的运气,没有...感谢您花时间找到该引文:)
【解决方案2】:

这个

int **arr = (int **)malloc(r * sizeof(int *));

是int * [r] 类型数组的动态分配,该数组是r 元素的数组,其类型为int *。

为了使声明更清晰,请考虑以下简单程序

#include <stdio.h>

int main(void) 
{
    char * s[] = { "Hello", " ", "user292174" };
    const size_t N = sizeof( s ) / sizeof( *s );

    char **p = s;

    for ( size_t i = 0; i < N; i++ ) printf( "%s", p[i] );
    putchar( '\n' );

    return 0;
}

它的输出是

Hello user292174

为简单起见,在程序中使用char 类型而不是int。

表达式中的数组指示符(极少数例外)被转换为指向其第一个元素的指针。

因此,由于数组s 的类型是char *,那么指向数组s 的第一个元素的指针将具有char ** 类型。

在问题的原始声明的情况下,动态分配的内存范围被解释为int * 类型的元素数组。并且将存在隐含数组的第一个元素的范围的起始地址分配给指针。所以指针的类型应该是 int **。

int **arr = (int **)malloc(r * sizeof(int *));

当数组的行数和列数在运行时计算时,通常使用这种分配来模拟二维数组。

例如

#include <stdio.h>
#include<stdlib.h>

int main(void) 
{
    size_t r = 2;
    size_t c = 3;

    int **arr = (int **)malloc( r * sizeof( int * ) );

    for ( size_t i = 0; i < r; i++ )
    {
        arr[i] = malloc( c * sizeof( int ) );
    }

    for ( size_t i = 0; i < r; i++ )
    {
        for ( size_t j = 0; j < c; j++ )
        {
            arr[i][j] = c * i + j;
        }
    }

    for ( size_t i = 0; i < r; i++ )
    {
        for ( size_t j = 0; j < c; j++ )
        {
            printf( "%d ", arr[i][j] );
        }
        putchar( '\n' );
    }


    for ( size_t i = 0; i < r; i++ )
    {
        free( arr[i] );
    }

    free( arr );

    return 0;
}

程序输出是

0 1 2 
3 4 5

如果编译器支持可变长度数组,则可以一次分配一个二维数组。例如

#include <stdio.h>
#include<stdlib.h>

int main(void) 
{
    size_t r = 2;
    size_t c = 3;

    int ( *arr )[c] = (int **)malloc( sizeof( int[r][c] ) );


    for ( size_t i = 0; i < r; i++ )
    {
        for ( size_t j = 0; j < c; j++ )
        {
            arr[i][j] = c * i + j;
        }
    }

    for ( size_t i = 0; i < r; i++ )
    {
        for ( size_t j = 0; j < c; j++ )
        {
            printf( "%d ", arr[i][j] );
        }
        putchar( '\n' );
    }

    free( arr );

    return 0;
}

porgram 输出如上图所示。

【讨论】:

    猜你喜欢
    • 2021-10-07
    • 2014-06-25
    • 1970-01-01
    • 2013-06-27
    • 2021-04-21
    • 2011-02-04
    • 1970-01-01
    • 1970-01-01
    • 2016-03-06
    相关资源
    最近更新 更多