首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C中的二维数组是如何变成一维数组的?

C中的二维数组是如何变成一维数组的?
EN

Stack Overflow用户
提问于 2012-02-03 00:15:38
回答 7查看 4.7K关注 0票数 5

如果有人能给我解释一下以下行为,我将不胜感激:

假设我声明了一个静态2D数组

代码语言:javascript
运行
复制
float buffer[NX][NY];

现在,如果我想填充这个数组,我注意到可以这样做:

代码语言:javascript
运行
复制
initarray(buffer, NX, NY);

#define INITDATAVAL 0.5

void initarray(void *ptr, int nx, int ny)
{
  int i, j;

  float *data = (float *) ptr;

  for (i=0; i < nx*ny; i++)
    {
      data[i] = INITDATAVAL;
    }
}

我的问题是,如果buffer是一个二维数组,那么一旦它被传递给initarray函数,它如何被用作一维数组呢?我正在努力理解它...

当静态分配2D数组时,分配的内存是连续的,但是如果buffer是动态分配的,是否可以使用这种方式?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2012-02-03 00:19:26

在内存中,具有3 x 4元素(即矩阵)的2D数组如下所示:

代码语言:javascript
运行
复制
A1 A2 A3 A4 B1 B2 B3 B4 C1 C2 C3 C4

因为底层存储是连续的,所以可以简单地将数组转换为指向第一个元素的指针,并使用单个偏移量访问所有元素(这种“强制转换”,在这种上下文中称为“衰减”,当buffer传递给initarray时会自动发生)。

(在此示例中,编译器会将诸如buffer[n][m]之类的表达式转换为buffer + n*NY+m,基本上,2D数组只是存储在1D数组中的2D数据的一种舒适的表示法)。

票数 8
EN

Stack Overflow用户

发布于 2012-02-03 00:17:13

首先,initarray应该接受float*参数,而不是void*

将数组转换为指针时,会丢失有关维度的类型信息。您实际上是将其转换为指向第一个元素的指针,并确认存储是连续的。

代码语言:javascript
运行
复制
char foo [2][2] = { {'a','b'}, {'c','d'} }; // Stored as 'a', 'b', 'c', 'd'

您可以使用模板保留维度信息。

代码语言:javascript
运行
复制
template <int W, int H>
void initarray (float (&input)[W][H]) {
    for (int x = 0; x < W; ++x) {
        for (int y = 0; y < H; ++y) {
            input [x][y] = INITDATAVAL;
        }
    }
}

int main () {
    float array [3][4];
    initarray (array);
}

这里,input是对给定类型数组的引用(而维数是完整类型的一部分)。模板参数推导将使用W=3H=4实例化initarray的重载。很抱歉使用行话,但这就是它的工作方式。

顺便说一句,您将不能使用指针参数调用此版本的initarray,但如果需要,您可以提供重载。我经常写这样的东西

代码语言:javascript
运行
复制
extern "C" void process (const char * begin, const char * end);

template <typename N>
void process (const char * (&string_list) [N]) {
    process (string_list, string_list + N);
}

我们的想法是提供最通用的接口,在单独的翻译单元或库中实现一次,然后提供更友好、更安全的接口。

代码语言:javascript
运行
复制
const char * strings [] = {"foo", "bar"};
int main () {
    process (strings);
}

现在,如果我更改了strings,就不必在其他地方更改代码了。我也不需要考虑的恼人细节,比如我是否正确地维护了NUMBER_OF_STRINGS=2

票数 4
EN

Stack Overflow用户

发布于 2012-02-03 00:28:27

数组是一系列连续的对象。

数组的数组也是一系列连续的对象,但这些对象恰好是数组,它们本身只是由它们在内存中端到端放置的元素组成。图片:

代码语言:javascript
运行
复制
float a[2][3];
a[0]                      a[1]
+-------+-------+-------++-------+-------+-------+
|float  |float  |float  ||float  |float  |float  |
|a[0][0]|a[0][1]|a[0][2]||a[1][0]|a[1][1]|a[1][2]|
|       |       |       ||       |       |       |
+-------+-------+-------++-------+-------+-------+

由于这是包含浮点数的一行中的一系列单元格,因此也可以将其视为包含6个浮点数的单个数组(如果通过适当的指针查看)。新图片:

代码语言:javascript
运行
复制
float* b(&a[0][0]);//The &a[0][0] here is not actually necessary
                   //(it could just be *a), but I think
                   //it makes it clearer.
+-------+-------+-------++-------+-------+-------+
|float  |float  |float  ||float  |float  |float  |
|*(b+0) |*(b+1) |*(b+2) ||*(b+3) |*(b+4) |*(b+5) |
|       |       |       ||       |       |       |
+-------+-------+-------++-------+-------+-------+
^       ^       ^        ^       ^       ^       
|       |       |        |       |       |       
b      b+1     b+2      b+3     b+4     b+5

如您所见,a[0][0]变成了b[0]a[1][0]变成了b[3]。整个数组可以看作是一系列浮点数,而不是一系列浮点数。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9115775

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档