我正在尝试将二维char数组传递给函数。我已经找到了如何用一维数组做到这一点,但我很难将其推断到如何处理我目前的情况。请参阅示例代码:
void foo( char ** bar ) {
}
int main () {
char mlady[100][100];
foo(mlady);
}
编译器暗示参数应该是char(*)类型100,但我无法编译。我也没有运气就尝试了很多暴力。
我很惊讶我在google / SO上找不到这个,但我想我使用了错误的关键字。
答案 0 :(得分:5)
将void foo( char ** bar )
更改为void foo( char bar[][100] )
。
将多维数组传递给函数时,不必指定第一个数组维。但是,必须向函数提供第二个(和后续)维度。
有关详细信息,请查看此C-Faq。
答案 1 :(得分:2)
定义多维数组时,字节在内存中连续排列。
例如:
char a[3][5];
将为您提供15个连续的内存字节,如下所示:
----------------------------------------------
| a + 0 | a + 1 | a + 2 | a + 3 | a + 4 |
----------------------------------------------
| a + 5 | a + 6 | a + 7 | a + 8 | a + 9 |
----------------------------------------------
| a + 10 | a + 11 | a + 12 | a + 13 | a + 14 |
----------------------------------------------
要引用a[x][y]
,编译器会将其转换为a + y + x * 5
,就像它将单个元素数组的索引从a[x]
转换为a + x
一样。
您将看到,为了使此转换适用于二维数组,您必须知道最右侧的维度。换句话说,定义5
中的char a[3][5]
出现在计算a + y + x * 5
中,并且必须出现在该计算中才能生效。
你不需要知道最左边的维度,因为它不会出现在计算中。
这通常适用于任何多维数组。为了计算指定索引的偏移量,您必须知道除最左边的维度之外的所有维度。拥有最左边的一个并没有什么坏处,但你不需要它。
另一种说法是C语言中的“多维数组”实际上只是处理一维数组的便捷方式。没有char a[3][5]
为您提供无法使用char a[15]
完成,并将a[x][y]
的所有实例替换为*(a + y + x * 5)
,它只会使语法更方便。在引擎盖下,这两种方式实际上是相同的。
因此,一方面,尝试将二维数组作为char **
传递给函数将不起作用,因为您没有为函数提供最右侧的维度,并且函数需要它。 void func(char (*bar)[5])
和void func(char bar[][5])
等同于此。在第一种情况下,您需要*bar
周围的括号,否则您将拥有void func(char *bar[5])
,其中bar
将被声明为指向char
的五元素数组,这根本不是你所拥有的。
更基本的是,将其作为char **
传递将不起作用,因为char **
是指向char
指针的指针,并且在二维char
数组中,你不会拥有任何char
指针 - 只有一堆普通的chars
。指向该数组的指针将被传递给该函数,但是当您取消引用它一次时,就没有更多的指针需要查找,并且要从char **
获取到char
,您需要依赖两次。
如果您要做类似的事情(为简洁起见省略了错误检查):
char ** list_strings = malloc(3 * sizeof *list_strings);
list_strings[0] = malloc(5);
list_strings[1] = malloc(5);
list_strings[2] = malloc(5);
然后你可以将list_strings
作为char **
传递,因为它实际上是一个,而不是真正的多维数组 - 那里有两个间接层,一次获取单个字符串,然后再次获取其中一个字符串中的单个字符。你传递给函数的是char *
的一维(动态分配)数组。事实上,你的函数可以继续推动任何这些成员再次使它成为一个多维数组。
当您以这种方式传递char **
时,从技术上讲,您不需要 来了解任何维度,至少不会访问任何特定元素。当然,你需要知道尺寸以避免函数从它们的任何一端掉落,除非你将数组的尺寸硬编码到你的函数中并且只传递那个大小的数组,这通常不是编写程序的好方法。