gpt4 book ai didi

c - 结构中的指针中不允许使用 VLA 有充分的理由吗?

转载 作者:太空宇宙 更新时间:2023-11-04 07:06:31 26 4
gpt4 key购买 nike

这是一种定义矩阵类型的方法

typedef struct {
int nr, nc;
double *elem;
} Matrix;

我想定义这个

typedef struct {
int nr, nc;
double elem[nr][nc];
} Matrix;

这很好,因为我不必担心索引。这就是 VLA 最初有用的原因,因为它们只透明地执行索引算法可以轻松完成的操作。

当然,上述情况是不可能的,因为结构的大小无法很好地定义。然后,我仍然会很高兴:

typedef struct {
int nr, nc;
double (*elem)[nc];
} Matrix;

现在,矩阵数据存储为指针,就像在非 VLA 情况下一样。但是运算仍然可以由编译器完成。该定义仅说明它是某种指向 double 数据的指针,double 排列在宽度为 nc 的数组中。

似乎标准也不允许这样做,我想知道为什么,因为通过转换很容易做到这一点。例如,使用第一个定义(使用 double *),我可以做到

double get(Matrix *a, int i, int j) {
int nc = a->nc;
double (*p)[nc] = (double (*)[nc])a->elem;
return p[i][j];
}

当然,这里不是很有趣,因为只有一个对 elem 的访问,但如果有很多,也可能是这样。

那么,我的问题,希望它切题:禁止第三个定义的真正原因是什么?

我可以想象这很危险,因为它不能保证 nc 处理正确的值,但无论如何这对于指针来说都是危险的,所以这看起来不是一个好的理由。

最佳答案

这是否符合您的要求?它在结构中存储一个 void *,访问函数将其转换为指向 2D VLA 的指针并使用它。 Mac OS X 10.10.5 上的 GCC 5.2.0 可以干净地编译它,valgrind(2014 年 11 月左右的 3.11.0-SVN)给它一个干净的健康证明。

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

typedef struct
{
int nr, nc;
void *data; // Actually double a[nr][nc]
} Matrix;

static double get(Matrix *a, int i, int j)
{
double (*array)[a->nr][a->nc] = a->data;
return (*array)[i][j];
}

static void set(Matrix *a, int i, int j, double v)
{
double (*array)[a->nr][a->nc] = a->data;
(*array)[i][j] = v;
}

static Matrix *mat_alloc(int nr, int nc)
{
Matrix *m = malloc(sizeof(*m));
if (m != 0)
{
m->nr = nr;
m->nc = nc;
m->data = malloc(nr * nc * sizeof(double));
if (m->data == 0)
{
free(m);
m = 0;
}
}
return m;
}

static void mat_free(Matrix *m)
{
free(m->data);
free(m);
}

int main(void)
{
int nr = 3;
int nc = 5;

Matrix *m = mat_alloc(nr, nc);
if (m == 0)
{
fprintf(stderr, "Matrix allocation for %dx%d matrix failed\n", nr, nc);
exit(1);
}

for (int i = 0; i < nr; i++)
{
for (int j = 0; j < nc; j++)
{
double v = (i * (nc + 1)) + j + 1;
set(m, i, j, v);
printf("Set: [%d,%d] = %4.1f\n", i, j, v);
}
}

for (int j = 0; j < nc; j++)
{
for (int i = 0; i < nr; i++)
printf("Get: [%d,%d] = %4.1f\n", i, j, get(m, i, j));
}

mat_free(m);
return 0;
}

我不确定是否有一种巧妙的方法来丢失访问函数中符号的 (*array) 部分。如果有的话我会更喜欢它(而不是使用 array[0][i][j],也就是说)。

示例运行

Set: [0,0] =  1.0
Set: [0,1] = 2.0
Set: [0,2] = 3.0
Set: [0,3] = 4.0
Set: [0,4] = 5.0
Set: [1,0] = 7.0
Set: [1,1] = 8.0
Set: [1,2] = 9.0
Set: [1,3] = 10.0
Set: [1,4] = 11.0
Set: [2,0] = 13.0
Set: [2,1] = 14.0
Set: [2,2] = 15.0
Set: [2,3] = 16.0
Set: [2,4] = 17.0
Get: [0,0] = 1.0
Get: [1,0] = 7.0
Get: [2,0] = 13.0
Get: [0,1] = 2.0
Get: [1,1] = 8.0
Get: [2,1] = 14.0
Get: [0,2] = 3.0
Get: [1,2] = 9.0
Get: [2,2] = 15.0
Get: [0,3] = 4.0
Get: [1,3] = 10.0
Get: [2,3] = 16.0
Get: [0,4] = 5.0
Get: [1,4] = 11.0
Get: [2,4] = 17.0

关于c - 结构中的指针中不允许使用 VLA 有充分的理由吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32565694/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com