c++ - 将 2D 数组 (T[N][M]) 作为大小为 N*M 的 1D 数组访问是否可以保证工作?
问题描述
我可以确定以下代码会起作用吗?
int sum_array(int *array, size_t size)
{
int i;
int sum = 0;
for (i=0;i<size;i++)
sum += *(array+i);
return sum;
}
int main()
{
int two_d_array[4][3] = {{1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}};
int sum = sum_array(&two_d_array[0][0], 12);
printf("%d", sum);
}
虽然将 4×3 数组完全按照 12 元素数组布局在内存中是有意义的,但是否可以保证?因为我似乎在欺骗类型系统,所以我不太确定会出现问题(例如,填充被添加到 int[3])。
如果您可以详细说明如果我在数组中使用整数以外的东西会发生什么,并提供标准中的相关报价,则可以加分。
解决方案
例如,填充被添加到 int[3]
没有那种危险。数组保证没有填充。内存布局本身是有保证的,而指针算法在技术上是未定义的,根据评论中提到的这个引用:expr.add/4因此:
2D 数组 (T[N][M]) 通过指针 (T*) 遍历是否保证有效?
不幸的是,技术上不符合我对标准的理解。
这是一个标准版本,std::accumulate
它迭代任何维度计数的多维数组的最里面的元素,就好像它是一个平面数组一样:
template<class T, unsigned size, class BinOp = std::plus<>>
auto arr_accumulate(
T (&arr)[size], std::remove_all_extents_t<T> init = {}, BinOp op = {})
{
if constexpr (std::is_array_v<T>) {
return std::accumulate(std::begin(arr), std::end(arr), init,
[&](const auto& l, const auto& r) {
return arr_accumulate(r, l, op);
}
);
} else {
return std::accumulate(std::begin(arr), std::end(arr), init, op);
}
}
// usage
int sum = arr_accumulate(two_d_array, 0);
我没有对此进行基准测试,看看是否有任何开销。在您的示例中使用编译时常量输入,总和是在编译时计算的。
另一种实现;仅适用于普通类型:
template<class T, unsigned size>
constexpr auto flat_size (T (&arr)[size]) {
using E = std::remove_all_extents_t<T>;
return sizeof arr / sizeof (E);
}
template<class T, unsigned size, class BinOp = std::plus<>>
auto arr_accumulate_trivial(
T (&arr)[size], std::remove_all_extents_t<T> init = {}, BinOp op = {})
{
using E = std::remove_all_extents_t<T>;
static_assert(std::is_trivially_copyable_v<E>);
std::array<E, flat_size(arr)> flat;
std::memcpy(flat.data(), arr, sizeof arr);
return std::accumulate(std::begin(flat), std::end(flat), init, op);
}
推荐阅读
- java - java.lang.NullPointerException 在循环中设置属性值时
- reactjs - 如何让 Google Analytics 与 React 一起工作
- php - 如何在另一个 php 标签和 echo 中实现一个 php 标签和 echo?
- javascript - 添加一个按钮来选择下拉菜单
- java - 为什么 SimpleDateFormat setTimeZone 不会为无效时区抛出错误
- visual-studio - Visual Studio:“没有测试与给定的测试用例过滤器匹配”,但仅在从顶层运行时?
- macos - 从 VS Code 在模拟器上同步应用程序非常慢
- node.js - 在nodeJS应用程序中查询mongoDB返回值void?
- python - Python3:打印带有从非 ASCII 字符(unicode_escape)的文本文件中读取的表情符号的文本
- spring - Spring security:如何使用自定义代码停止链?