返回malloc’ed矩阵,同时能够使用下标符号
我有一个练习,我应该使用固定大小的数组和输入/输出参数来处理矩阵(添加,扫描,打印等),但我想在任意长度的矩阵上做它并返回它们不是每次都添加更多(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等常量值,我也得到“无效的初始化器”. 我通过差不多一个星期的搜索,也许这是不可能的,我应该继续前进…我也发现了这个符号,对我来说看起来像函数指针表示法,除非它是一个优先考虑*运算符的方法… int (*tab)[x][y]=malloc(x*y*sizeof(int)); 但是我并不完全确定理解这种表示法,因为这样就可以从打印/填充数组中获取随机值. 以前我曾尝试使用VLA(可变长度数组)和GNU扩展来提供数组长度作为参数: void printMat (int h,int w; int tab[h][w],int h,int w) { [code using tab[x][y]] } 但我很快就意识到我需要用指针和malloc来处理一个“添加”函数,添加两个矩阵并返回一个指向新malloc’ed矩阵的指针…… 我特别想知道,如果我不够具体,我应该如何声明参数和返回类型,以便能够将它们用作多维数组而不必使用中间变量,同时实际传递指针(无论如何,这已经是正常的多维数组作为参数做对了吗?) 好吧经过多次测试和尝试后,它现在按照我的意图工作,即使我不确定是否已经很好地理解了所有内容,特别是指针是什么,什么不是(我可能会因为试图弄清楚gdb这个而感到困惑,我应该进一步调查一下,正常的单维或多维数组是否被gdb视为地址,等等),而今天我的睡眠/休息时间并没有达到最佳状态. 现在,我想对我最初问题的第二部分给出正确答案:如何回归?是否有一个适当的泛型类型(除了无意义的void *),它可能被用于指向二维数组的指针(如int(*)[] []但是这会起作用吗?)?如果太通用,什么是投射返回指针的正确方法,所以我可以使用多维下标表示法?是(int(*)[3] [3])对吗? 然而,如果我没有得到任何令人满意的结果(一个合理的 – 足够的“它在C中是不可能的”我猜),我会设置@JohnBod当前的答案来解决问题,因为他通过一个完整的确定了多维vla malloc多维数组的解释性答案,完全回答问题的第一部分,并在第二部分的路径上给出了几个答案(如果有的话). #include <stdio.h> #include <stdlib.h> void print_mat (int x,int y; int mat[x][y],int x,int y) { for (int i = 0; i < x; i++) { for (int j=0; j < y ; j++) printf("%d ",mat[i][j]); putchar('n'); } putchar('n'); } void* scan_mat (int x,int y) { int (*mat)[x][y]=malloc(sizeof(*mat)); for (int i = 0; i < x ; i++) for (int j = 0; j < y; j++) { printf("[%d][%d] = ",i,j); scanf("%d",&((*mat)[i][j])); } return mat; } void* add_mat (int x,int y; int mat1[x][y],int mat2[x][y],int y) { int (*mat)[x][y]=malloc(*mat); #pragma GCC ivdep for (int i = 0; i < x ; i++) for (int j = 0; j < y; j++) (*mat)[i][j]=mat1[i][j]+mat2[i][j]; return mat; } int main () { int mat1[3][3] = {1,2,3,4,5,6,7,8,9},(*mat2)[3][3] = scan_mat(3,3); print_mat(mat1,3); print_mat(*mat2,3); print_mat((int(*)[3][3])add_mat(mat1,*mat2,3),3); // both appears to work… array decay? print_mat(*(int(*)[3][3])add_mat(mat1,3); printf("%dn",(*(int(*)[3][3])add_mat(mat1,3))[2][2]); return 0; } 和输入/输出: [0][0] = 1 [0][1] = 1 [0][2] = 1 [1][0] = 1 [1][1] = 1 [1][2] = 1 [2][0] = 1 [2][1] = 1 [2][2] = 1 1 2 3 4 5 6 7 8 9 1 1 1 1 1 1 1 1 1 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 10 解决方法
如果要分配类型为T的缓冲区,则典型的过程是
T *ptr = malloc( sizeof *ptr * N ); // sizeof *ptr == sizeof (T) 你正在为类型T的N个元素分配足够的空间. 现在让我们用数组类型R [M]替换T: R (*ptr)[M] = malloc( sizeof *ptr * N ); // sizeof *ptr == sizeof (R [M]) 你为R类型的N个元素分配了足够的空间[M] – IOW,你刚刚为N的N个M数组分配了足够的空间.注意语义与上面T的数组完全相同;所有改变的是ptr的类型. 将其应用于您的示例: int (*tab)[y] = malloc( sizeof *tab * x ); 然后,您可以像任何2D数组一样索引选项卡: tab[x][y] = new_value(); 编辑 回答评论:
subscript []和函数call()运算符的优先级高于一元*,所以声明就像 int *a[N]; 被解析为 int *(a[N]); 并声明一个指向int的指针数组.要声明指向数组的指针,必须使用标识符显式地对*运算符进行分组,如下所示: int (*a)[N]; 这声明了一个指向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)); 将制表符声明为指针的2D数组,而不是指向2D数组的指针,并且对malloc(…)的调用不是2D数组对象的有效初始值设定项. 语法 int (*tab)[x][y]=malloc(x*y*sizeof(int)); 将tab声明为指向2D数组的指针,对malloc的调用是一个有效的初始化器. 但… 使用此声明,您必须在索引之前显式取消引用选项卡,如下所示: (*tab)[i][j] = some_value(); 您没有索引到标签,您正在索引到哪个标签指向. 请记住,在C语言中,声明模拟使用 – 声明中的声明符结构与可执行代码中的声明形式相匹配.如果您有一个指向int的指针,并且您想要访问指向的值,则使用unary *运算符: x = *ptr; 表达式* ptr的类型是int,因此写入ptr的声明 int *ptr; 对于数组也是如此,如果数组的第i个元素的类型为int,则表达式arr [i]的类型为int,因此arr的声明被写为 int arr[N]; 因此,如果您将制表符声明为 int (*tab)[x][y] = ...; 然后要索引它,你必须写 (*tab)[i][j] = ...; 我展示的方法避免了这种情况.请记住,数组下标操作a [i]定义为*(a i) – 给定地址a,偏移i元素(不是字节!)并取消引用结果.因此,以下关系成立: *a == *(a + 0) == a[0] 这就是为什么你可以在指针表达式和数组表达式上使用[]运算符.如果您将缓冲区分配为 T *p = malloc( sizeof *p * N ); 你可以像p [i]一样访问每个元素. 所以,给出一个类似的声明 T (*a)[M]; 我们有这种关系 (*a)[i] == (*(a + 0))[i] == (a[0])[i] == a[0][i]; 因此,如果我们将数组分配为 T (*a)[M] = malloc( sizeof *a * N ); 然后我们可以索引一个as的每个元素 a[i][j] = some_value(); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |