返回malloc’;在能够使用下标表示法的情况下对矩阵进行加密

返回malloc’;在能够使用下标表示法的情况下对矩阵进行加密,c,arrays,pointers,multidimensional-array,variable-length-array,C,Arrays,Pointers,Multidimensional Array,Variable Length Array,我有一个练习,我应该使用固定大小的数组和输入/输出参数来处理矩阵(add、scanf、print等),但我希望对任意长度的矩阵进行处理并返回它们,而不是每次添加更多(in/)输出参数(因此可能允许更“功能性”的样式) 由于我想返回它们,我想我可能需要malloc来保持内存中的数组通过函数作用域。由于我想使用多维下标符号(mat[x][y],而不是mat[x*len+y]或mat+x*len+y),我想我应该使用某种vla或强制转换……但似乎禁止对数组强制转换(但我经常返回指针,如果我不能强制转换

我有一个练习,我应该使用固定大小的数组和输入/输出参数来处理矩阵(add、scanf、print等),但我希望对任意长度的矩阵进行处理并返回它们,而不是每次添加更多(in/)输出参数(因此可能允许更“功能性”的样式)

由于我想返回它们,我想我可能需要malloc来保持内存中的数组通过函数作用域。由于我想使用多维下标符号(
mat[x][y]
,而不是
mat[x*len+y]
mat+x*len+y
),我想我应该使用某种vla或强制转换……但似乎禁止对数组强制转换(但我经常返回指针,如果我不能强制转换,如何对它们使用下标符号?),我显然 “可能不会初始化可变大小的对象”,正如编译器所说(即使它不是直接的数组,而是指向数组的指针),如使用以下符号:

int *tab[x][y]=malloc(x*y*sizeof(int));
如果我手动将x和y替换为常量值(如
3
),我也会得到“无效初始值设定项”

我花了将近一周的时间进行搜索,也许这是不可能的,我应该继续前进……我还发现了这个符号,它对我来说就像函数指针符号,除非它是一种对
*
操作符进行优先级排序的方法

int (*tab)[x][y]=malloc(x*y*sizeof(int));
然而,我不能完全理解这种表示法,因为这样可以从打印/填充的数组中获得随机值

之前,我尝试使用VLAs(可变长度数组)和GNU扩展来指定数组长度作为参数:

void
printMat (int h, int w; int tab[h][w], int h, int w)
{
   [code using tab[x][y]]
}
但我很快意识到我需要处理指针和malloc,因为“add”函数需要添加两个矩阵并返回指向新的malloc矩阵的指针


我特别想知道,如果我不够具体,我应该如何声明参数和返回类型,以便能够将它们作为多维数组使用,而不必使用中间变量,同时实际传递指针(无论如何,这已经是将普通多维数组作为参数传递的内容了,对吗?)


好的,经过多次测试和尝试,它现在按照我的预期工作,即使我不确定是否正确理解了所有内容,特别是什么是指针,什么不是指针(我可能在试图弄清楚gdb时弄糊涂了,我可能应该进一步研究一个普通的单或多维数组是否被gdb视为地址,等等),因为今天我的睡眠/休息和注意力都没有达到最佳状态

现在,我想正确回答我的第一个问题的第二部分:如何返回?是否有一个正确的泛型类型(除了无意义的
void*
)可能适用于指向二维数组的指针(如
int(*)[][]
,但这会起作用?)?如果太泛型,如何正确地转换返回指针,以便在其上使用多维下标符号?
(int(*)[3][3])
正确吗

然而,如果我对此没有得到任何满意的结果(我想一个足够合理的“C中不可能”就可以了),我将@JohnBod current answer设置为解决问题,因为他通过多维数组的完整和解释性答案确认了多维vla malloc,完全回答了问题的第一部分,并在通往第二部分的路径上给出了多个答案(如果有)


如果要分配类型为
T
的缓冲区,典型的过程是

T *ptr = malloc( sizeof *ptr * N ); // sizeof *ptr == sizeof (T)
您正在为类型为
T
N
元素分配足够的空间

现在,让我们将
T
替换为数组类型
R[M]

R (*ptr)[M] = malloc( sizeof *ptr * N  ); // sizeof *ptr == sizeof (R [M])
您为
N
类型
R[M]
的元素分配了足够的空间-瞧,您刚刚通过
M
数组
R
N
分配了足够的空间。请注意,语义与上面的
T
数组完全相同;所更改的只是
ptr
的类型

将其应用于您的示例:

int (*tab)[y] = malloc( sizeof *tab * x );
然后,您可以像索引任何二维数组一样索引
选项卡

tab[x][y] = new_value();
编辑

答复评论:

然而,我仍然不知道“(*tab)”语法的含义是什么?我猜它不是一个函数指针,但为什么没有括号的*tab不起作用:实际的不同含义是什么?为什么它不起作用,然后会发生什么变化

下标
[]
和函数调用
()
运算符的优先级高于一元
*
,因此

int *a[N];
T (*a)[M];
被解析为

int *(a[N]);
并将
a
声明为指向
int
的指针数组。若要声明指向数组的指针,必须使用标识符显式地将
*
运算符分组,如下所示:

int (*a)[N];
(*tab)[i][j] = some_value();
这将
a
声明为指向
int
数组的指针。同样的规则也适用于函数声明。下面是一个方便的摘要:

T *a[N];    // a is an N-element array of pointers to T
T (*a)[N];  // a is a pointer to an N-element array of T
T *f();     // f is a function returning pointer to T
T (*f)();   // f is a pointer to a function returning T
在代码中

int *tab[x][y]=malloc(x*y*sizeof(int));
tab
声明为指针的2D数组,而不是指向2D数组的指针,并且对
malloc(…)
的调用不是2D数组对象的有效初始值设定项

语法

int (*tab)[x][y]=malloc(x*y*sizeof(int));
tab
声明为指向2D数组的指针,对
malloc
的调用是该数组的有效初始值设定项

但是

使用此声明,您必须在索引到
选项卡之前显式取消引用它,如下所示:

int (*a)[N];
(*tab)[i][j] = some_value();
您没有索引到
选项卡
,而是索引到
选项卡
指向的内容

请记住,在C语言中,声明模拟使用-声明中声明符的结构与它在可执行代码中的外观相匹配。如果有指向
int
的指针,并且希望访问指向的值,则使用一元
*
运算符:

x = *ptr;
类型
int arr[N];
int (*tab)[x][y] = ...;
(*tab)[i][j] = ...;
*a == *(a + 0) == a[0]
T *p = malloc( sizeof *p * N );
T (*a)[M];
 (*a)[i] == (*(a + 0))[i] == (a[0])[i] == a[0][i];
T (*a)[M] = malloc( sizeof *a * N );
a[i][j] = some_value();