float(*vals)[n] = malloc(sizeof(float[n]))有什么作用?

问题描述 投票:0回答:2

维基百科页面解释了什么是可变长度数组 (VLA),列出了以下 C99 示例代码:

float read_and_process(int n)
{
    float (*vals)[n] = malloc(sizeof(float[n]));

    for (int i = 0; i < n; ++i)
        (*vals)[i] = read_val();

    float ret = process(n, *vals);
    
    free(vals);
    
    return ret;
}

陈述

通过使用指向数组的指针,可以使用具有动态存储的类似 VLA 的语法。

该页面上显示的真正的 C99 VLA 代码是

float read_and_process(int n)
{
    float vals[n];

    for (int i = 0; i < n; ++i)
        vals[i] = read_val();

    return process(n, vals);
}

此代码很可能导致数组位于堆栈上,但这并不能保证(C 标准没有定义此类 VLA 必须位于何处)并且也不相关,只要正确释放内存即可再次

read_and_process()
返回。

维基百科页面的替换代码使用

malloc()
free()
,因此内存将位于
malloc()
保留内存的位置,通常是堆。但是这里的
*vals
有什么作用呢?

我的问题是:替换版本与以下代码有何不同:

float read_and_process(int n)
{
    float *vals = malloc(sizeof(float) * n);

    for (int i = 0; i < n; ++i)
        vals[i] = read_val();

    float ret = process(n, vals);

    free(vals);

    return ret;
}

真正的 VLA 版本中的

process()
不会像上面的版本一样获取指向数组的指针吗?那为什么替换版本中要传入
*vals
呢?

arrays c memory-management
2个回答
0
投票

区别在于

vals
的类型。

在替换版本中,

vals
的类型是
float (*)[n]
,而在您的版本中,
vals
的类型是
float *
。他们俩是不同的。

float (*vals)[n]

vals
是指向
n
float
数组的指针,即指向
float [n]
的指针。

当您取消引用

vals
*vals
时,它会给出
float [n]
类型,当它作为参数传递给函数时,会转换为指向
float
数组的第一个元素的指针,因为事实上, C,转换为指向数组对象初始元素的指针类型的数组(此规则有一些例外)。
这就是
*vals
被传递到替换版本中的
process()
函数的原因。


0
投票

该构造在将 2D 数组传递给函数时具有优势。


如果没有特殊指针,我们将不得不手动处理行索引:

void
process(int w,int h,float *arr)
{

    for (int y = 0;  y < h;  ++y) {
        for (int x = 0;  x < w;  ++x)
            arr[(y * h) + x] = (y * h) + x;
    }
}

使用特殊指针,我们可以传递维度:

void
process(int w,int h,float (*arr)[n])
{

    for (int y = 0;  y < h;  ++y) {
        for (int x = 0;  x < w;  ++x)
            arr[y][x] = (y * h) + x;
    }
}

举个例子,这是我最近的一个答案,其中我将 2D 数组的

double **
伪实现(pointers 数组到
double
数组)转换为“真正的”2D 数组: OpenMP并行化效率非常低

© www.soinside.com 2019 - 2024. All rights reserved.