我想把一个二维数组传递给一个函数,但是,我想用 arbitrary size来做这件事。
首先,请看以下代码:
#define MAX_ROWS 8
#define MAX_SIZE 32
static void foo(char array[][MAX_SIZE], size_t max_rows, size_t max_size) {
for (size_t i = 0; i < max_rows; i++) {
printf("%s\n", array[i]);
}
}
int main(void) {
char array[MAX_ROWS][MAX_SIZE];
for (size_t i = 0; i < MAX_ROWS; i++) {
snprintf(array[i], MAX_SIZE, "Row: %d", i);
}
foo(array, MAX_ROWS, MAX_SIZE);
return 0;
}
***但有一句我不喜欢:
static void foo(char array[][MAX_SIZE], size_t max_rows, size_t max_size)
我不喜欢它,因为我不仅需要指定两次最大大小,我还需要硬编码第二维的最大大小,以便在编译时可用。
**B.**另一种方法是创建可变长度数组(VLA)。为此,我们需要改变参数的顺序,使size_t max_size
出现在数组之前:
static void foo(size_t max_rows, size_t max_size, char array[][max_size])
foo(MAX_ROWS, MAX_SIZE, array);
一方面我喜欢这个解决办法,但另一方面我又不喜欢。它是C99标准的一部分,但不受MSVC支持。所以,我根本不能使用它。
此外,我不确定这种使用是否会由于安全原因而被劝阻,即使大小-由于使用宏常量-仍然 * 事实上 * 硬编码,因此实际上不是可变的。
**C.**据我所知,char array[MAX_ROWS][MAX_SIZE]
在内部只是一个大小为max_rows * max_size * sizeof(char)
的缓冲区。因此,我在考虑以下解决方案,但结果是Segmentation Fault
:
static void foo(void *array0, size_t max_rows, size_t max_size) {
size_t total_size = max_rows * max_size * sizeof(char);
char *array = malloc(total_size);
memcpy(array, array0, total_size);
for (size_t i = 0; i < max_rows; i++) {
printf("%s\n", array[i]);
}
free(array);
}
4条答案
按热度按时间wkyowqbh1#
你可以在
char *
上使用指针运算,这是像qsort这样的函数在不知道传递数组的具体类型时的操作方式:输出量:
关于C-FAQ:
然而,必须指出,以这种方式“手工”执行多维数组下标的程序并不严格符合ANSI C标准;根据官方的解释,访问(&array[0][0])[x]的行为并没有定义为x >= NCOLUMNS。
因此,这个答案(以及@0_使用行优先顺序提供的另一个答案)并不严格符合标准。
cngwdvgl2#
备注:
C
没有像FORTRAN
那样的多维数组。只有数组。int array[40]
。C
可以有任何数组,所以数组可以是数组的数组,数组的数组的数组,等等。示例
考虑这段简单的代码
这表明在测试运行中
如果我们检查这个地址的内存
我们在运行时看到数组数据在预期的地址
返回原始代码
这段代码试图将一个字符串数组传递给
foo()
函数。例如,这是
main
的通用原型,适用于每个C
程序:它做同样的事情。一直都很有效。类型不同,因为
foo()
声明的是但是在
foo()
内部,只能通过调用printf()
来访问行,而
%s
用于空终止字符串,因此foo()
中的char_array
非常类似于每个C
程序中的argv
从
char block[10][20]
到char** line
在
block
中,我们有一个200字节的连续数据块。line
是一个指针。block[0]
是char[20]
,最多可以有19个char
加上终止NULL
。block[0]
到block[9]
,我们可以有10个这样的字符串。line
也可以看作是一个数组。这是C
* 数组到指针衰减 * 的事情。*line
是char*
。它是*
运算符的结果。line[0]
与*line
相同。C
* 指针运算:line[0]
=*(line + 0)
。**line
是单个char
。第一个字符串的第一个字母,如block
中的block[0][0]
但是我们如何知道
block
中有多少行和多少行呢?line
中有多少个指针?我们没有。我们需要保留其他地方保存的维度,或者我们计算:这就是为什么我们需要
strlen()
来随时计算字符串大小的原因。类似的东西肯定可以用于line
,在line
的末尾使用NULL
指针这就是在
main
中使用argc
的原因:在argv
数组中保存指针的数量封装及示例
我将使用这种封装思想编写一个示例,将数据封装在
struct
中,并编写最少的函数来操作它。使用
char**
就像系统为
main
构建一个数组一样,我们将在line
中创建argv
数组:每个块都是空的,大小=
limit
。如果需要,可以根据一组incr
指针调整大小。原因是:重新分配存储器在时间方面可能是昂贵的,因为可能需要复制整个阵列。Block
函数最低检测要求。函数名是自解释的。
show_blk()
接受opional消息resize()
仅用于扩展。如果需要,缩小尺寸是rivial一个可能的实现,一个使用的例子是在这篇文章的结尾
测试用函数helper
这个函数只是将一个文件加载到一个新的
Block
中,并返回Block
地址。测试功能的简单方法。main()
进行测试此程序要求在命令行上显示文件名。然后
Block
文件中的所有行qsort()
对块内的所有行进行排序struct
中的命令行p.exe stuff.h
输出下面是使用文件
stuff.h
进行测试的输出stuff.h stuff.c main.c
完整代码【本次测试】stuff.h
stuff.c
main.c
没有真正测试过,但它显示了一种写这种东西的方法。由于代码在
stuff.c
文件中,因此可以在几分钟内在任何程序中使用。只包含stuff.h
。qnzebej03#
在我的情况下,最好的方法-正如@tstanisl所建议的那样-是更改编译器以使用VLA,确切地说:为了使用VMT,一个可变修改的类型。这不仅是C99标准的一部分,而且在即将到来的C23中是强制性的(参见here),所以我错误地认为这是不鼓励的。
在我的例子中,我将编译器改为Clang。MSVC中的Clang支持可以安装在
New Project > Installed > Templates > Visual C++ > Cross Platform
然后在
Project Properties > Configuration Properties > General > Platform Toolset
。x8goxv8g4#