这是一个有很多答案的问题,但没有一个做具体的事情。
我试着查看所有这些帖子-123456789-每次的解决方案要么是使用VLA,要么是使用固定维度的普通数组,要么是使用指针到指针。
我要分配的是:
- 动态(在运行时使用变量集)
- 矩形(“二维数组”)(我不需要锯齿形的数组。而且我想无论如何都不可能做到。)
- 连续内存(在#8和其他一些帖子中,人们说指针到指针是坏的,因为堆填充和碎片)
- 没有vla(我听说他们是魔鬼,并始终避免他们,不要与人谁建议使用他们在任何情况下)。
所以,如果有一篇文章我跳过了,或者没有读得足够透彻,符合这些要求,请给我指出来。
否则,我会请你教育我这一点,告诉我这是否可能,如果可能,如何做到这一点。
5条答案
按热度按时间qyuhtwio1#
您可以将连续的2D数组动态配置为
然后访问元素
arr[i][j]
。如果您的编译器不支持VLA,则
cols
必须是常量表达式。dnph8jn42#
初步评估
如果你想让你的代码与微软的C编译器一起工作,VLA是一个问题,因为微软一直拒绝实现VLA支持,即使C99是当前的语言标准,其中VLA支持是强制性的。一般来说,我会建议如果可以的话,完全避免使用微软的C编译器,但我不会建议避免使用那些给你不同建议的人。
当你声明一个VLA类型的自动对象而不管理最大维时,VLA也是一个潜在的问题。尤其是当维来自用户输入时。这会产生程序崩溃的风险,除非首先避免这种情况,否则很难在开发时测试或减轻这种风险。
但称VLA为“魔鬼”充其量是过于戏剧化的,我建议,任何实际告诉你“不要与建议在任何场景中使用它们的人交谈”的人一定不相信你能理解所涉及的问题或亲自评估它们。特别是,指向VLA的指针是一种很好的方式来解决你除了“没有VLA”之外的所有观点,并且除了缺乏(主要是)微软的支持之外,它们没有特别的技术问题。对这些的支持将在C2 X中再次成为强制性的,C2 X是下一个C语言规范,尽管对一些其他形式的VLA使用的支持将仍然是可选的。
您的要求
如果数组类型的任何维度不是由整数常量表达式给出的,那么根据定义,该类型是可变长度数组类型。如果数组类型的任何维度(除了第一个维度)不是由整数常量表达式给出的,那么不使用VLA就不能表达相应的指针类型。
因此,如果你想要一个连续分配的多维数组(数组的数组),并且在运行时为它选择除第一个维度之外的任何维度,那么必须涉及一个VLA类型。动态分配这样的对象效果很好,除了缺少某些编译器的支持(这是一个不可忽视的考虑因素)之外,几乎没有什么缺点。它看起来像这样:
您应该在问题中提到的一些问答中看到过类似的内容。
如果这是不可接受的,那么你需要选择给予哪些其他要求。我建议“多维”部分。相反,分配(有效地)一个一维数组,并通过在访问时执行适当的索引计算来像使用二维数组一样使用它。因为它与编译器为多维数组自动设置的内容非常接近。您可以通过创建一个宏来帮助计算,
或者,你可以给予连续分配而使用指针数组。这是那些不了解数组、指针和/或动态分配的人通常会做的事情,尽管有一些应用,特别是对于指向字符串的指针数组,这种形式的缺点主要是相对于连续分配的应用程序类型,其中人们想要一个对象,他们认为是一个2D数组。
kx7yvsdv3#
通常分配指针数组,然后将内存分配给每个指针。
分配一个大的连续内存块。分配一个指针数组,并从连续内存块中分配地址。
xwbd5t1u4#
假设您需要一个大小为
W
xH
的二维数组,其中包含int
s(其中H
是行数,W
是列数)。然后,您可以执行以下操作:
分配方式:
位置(i,j)处的访问元素:
整个数组将占用一个连续的内存块,并且可以动态分配(没有VLA)。作为一个连续的内存块比指针数组具有优势,因为[潜在地]更少的缓存未命中。
在这样的数组中,术语“stride”指的是一行到另一行之间的偏移量。如果你需要使用填充,例如,确保所有行都从某个对齐的地址开始,你可以使用大于
W
的stride。7y4bm7vi5#
我做了一个基准间:
a[x * COLS + y]
访问TL;DR:
第二个看起来比其他的快2-12%,其他的在性能上是类似的。
虽然这可能不是最好的方法,因为结果可能会被随机的东西污染--比如复制函数的源数组和目标数组的接近度(尽管读和写的数字是一致的。也许有人可以在这方面进行扩展)。