给我的问题具体说明函数采用整数2d数组和大小作为参数。那意味着, 1)我不允许在声明中定义数组的大小。 2)我必须将行数和列数传递给函数。
我以前为1D数组做过它并且它有效,但是在2D数组的情况下它会产生语法错误。我制作了测试代码来检查语法的逻辑。这是有效的一维数组逻辑。 此模块也要求我只使用C中的stido.h库。传递数组大小的原因是在不同的函数中填充数组,其中循环条件将使数组大小通过索引
#include<stdio.h>
void print(int table[],int r);
int main()
{ int r=7,table[r];
print(table,r);
}
void print(int table[],int r)
{ printf("table rows is%d\n",r);
}
然而,当我尝试2D数组时,这个相同的逻辑不起作用。(给出语法错误)
#include<stdio.h>
void print(int table[][],int c,int r);
int main()
{int c=7,r=7,table[c][r];
print(table,c,r);
}
void print(int table[][],int c,int r)
{printf("table rows is\ntable cols is\n",r,c)
}
有人可以解释为什么会这样,并建议解决这个问题。 ? 提前致谢
答案 0 :(得分:4)
您无法获得具有未指定尺寸的2D数组。但是,您似乎有一个C99 +编译器,因此可以使用可变长度数组。但是,您还需要重新排序参数。
请注意,我在这里使用size_t
而不是int
作为索引/维度 - 因为可能有一个表(尽管不太可能),其中包含的元素数多于{{1 }}
int
它在C99中编译,(以及那些支持可选VLA扩展的C11编译器);并且在运行时打印
#include <stdio.h>
#include <stdlib.h>
void print(size_t, size_t, int [*][*]);
int main(void) {
size_t c = 7, r = 9;
int table[c][r];
print(c, r, table);
}
void print(size_t c, size_t r, int table[c][r]) {
printf("table rows is %zu\ntable cols is %zu\n", r, c);
}
答案 1 :(得分:3)
首先,你想知道为什么这是不可能的。语言标准不允许这样做,技术原因是当第二个维度未知时,编译器无法计算数组的偏移量。
2D数组就像一维数组一样,一个接一个地存储在内存中。与其他一些语言一样,不是数组。使用像int a[5][3]
这样的2D数组,您连续5次int
次,全部在15 int
次。为了访问元素,编译器将为您计算偏移量,因此如果您编写例如a[2][2]
,这是第2*3 + 2
个元素(第三行的开头有两行3列要跳过)。
如果编译器不知道第二个维度,则此计算的offets 不可能。
Antti Haapala's answer已经展示了如何使用C99功能可变长度数组来解决这个问题。这是一个很好的方法,但不幸的是,对于C11,此功能是可选,因此可能有编译器不支持它。如果您确定只使用支持 VLA 的编译器(这是所有现代C编译器的绝大多数),请使用此答案中的代码。
当将数组传递给函数而不是数组时,会传递指向其第一个元素的指针(数组衰减作为指针)。所以以下声明是相同的:
void print(size_t n, int arr[]);
void print(size_t n, int *arr);
有了这些知识,你可能会想要用不同的方式写它并自己做偏移计算:
void print(size_t r, size_t c, void *data)
{
int *arr = data;
// access arr[2][2]:
int v = arr[2*c + 2];
}
事实上,这很可能会奏效,但请注意,这是未定义的:int[]
和int[][]
不兼容。有关此想法的详细信息,请参阅this question,其中包含两个非常有趣的答案。底线:这种代码的概率非常高。不过,可以肯定的是,不要这样做......
所以,如果你没有可变长度数组,如果你不想依赖于没有完美定义的东西,唯一的另一种方法是实际上通过一个指针数组构建一个数组
int row1[3] = {0, 1, 2};
int row2[3] = {3, 4, 5};
int *rows[2] = { row1, row2 };
然后你可以这样传递:
void print(size_t r, size_t c, int **arr)
{
int a = arr[0][2]; // 2
}
当然,这不再是 2D阵列,它是一种替代构造,可以以类似的方式使用。
答案 2 :(得分:1)
您无法为最终尺寸传递没有定义常量的2D数组。 (没有C99 VLA补充)。但是,您可以在print
中更改参数的顺序,以便在将r
声明为指向int [r] 数组的指针之前定义table
,并传递table
如下,例如
#include<stdio.h>
void print (int c, int r, int (*table)[r]);
int main (void) {
int c = 7, r = 7, table[c][r];
for (int i = 0; i < r; i++)
for (int j = 0; j < c; j++)
table[i][j] = i * j + i + j;
print (c, r, table);
return 0;
}
void print (int c, int r, int (*table)[r])
{
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++)
printf (" %3d", table[i][j]);
putchar ('\n');
}
}
此方法适用于使用带有C99 VLA扩展的VLA。
示例使用/输出
$ ./bin/fpass2d
0 1 2 3 4 5 6
1 3 5 7 9 11 13
2 5 8 11 14 17 20
3 7 11 15 19 23 27
4 9 14 19 24 29 34
5 11 17 23 29 35 41
6 13 20 27 34 41 48
如果VLA扩展不可用,您可以通过分配然后手动将2D阵列索引为1D阵列来解决此问题。这是因为2D数组是按顺序存储在内存中的数组数组(例如a[2][3]
在内存中是a00,a01,a02,a10,a11,a12
。)为了防止任何未定义的行为,您可以为table
分配存储空间(例如int *p = malloc (sizeof table);
复制table
,然后将每个调用print (p, c, r)
的元素编入索引,如下所示,例如
void print (int *table, int c, int r)
{
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++)
printf (" %3d", table[i * r + j]);
putchar ('\n');
}
}
table
用table[i * r + j]
编入索引以访问2D数组的每个原始元素。虽然这种方法是一种解决方法,但没有VLA扩展,您可能会为最终数组维度传递一个已定义的常量,从而使得变通方法或参数顺序的更改变得不必要。
仔细看看,如果您有疑问,请告诉我。
答案 3 :(得分:0)
首先,函数参数的类型衰减为指向数组第一个元素的指针。也就是说,以下声明对完全等效:
void f(int a[]);
void f(int *a);
void g(int a[][7]);
void g(int (*a)[7]);
void h(int a[][7][6]);
void h(int (*a)[7][6]);
现在,当您索引数组时,该操作实际上是根据指针算法定义的。因此,表达式a[3]
实际上等同于*(a + 3)
。
在这个表达式中,a
产生一个指向数组第一个元素的指针,并且相加会添加偏移量以跳过数组的三个元素。也就是说,机器将执行此计算:*(elementType*)((char*)a + 3*sizeof(elementType))
这方面的关键部分是sizeof(elementType)
:如果a
的类型为int[][]
,则其元素的类型为int[]
,您无法接受由于显而易见的原因,未知长度的数组的大小。因此,必须知道除最外层维之外的所有数组维的类型,以便能够索引到多维数组。
对于正在发生的事情的解释非常重要。你的后果是,你必须提供内部尺寸的大小。正如其他答案所示,这可以通过首先简单地排序大小参数来完成,因此它们可用于数组参数的声明:
void print(int c, int r, int table[c][r]);
或者,等效地,因为c
的值实际上在上面的声明中被忽略了:
void print(int rowCount, int columnCount, int (*table)[columnCount]) {
printf("table has %d columns and %d rows\n", columnCount, rowCount);
for(int curRow = 0; curRow < rowCount; curRow++) {
for(int curColumn = 0; curColumn < columnCount; curColumn++) {
printf("%d ", table[curRow][curColumn]);
}
printf("\n");
}
}
(在最后一个例子中,我冒昧地使用了正确的格式和变量名。请不要只使用单个字符作为变量名称,这与数组维度大小一样重要。)