C语言 多维数组如何在内存中格式化?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2565039/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How are multi-dimensional arrays formatted in memory?
提问by Chris Cooper
In C, I know I can dynamically allocate a two-dimensional array on the heap using the following code:
在 C 中,我知道我可以使用以下代码在堆上动态分配一个二维数组:
int** someNumbers = malloc(arrayRows*sizeof(int*));
for (i = 0; i < arrayRows; i++) {
someNumbers[i] = malloc(arrayColumns*sizeof(int));
}
Clearly, this actually creates a one-dimensional array of pointers to a bunch of separate one-dimensional arrays of integers, and "The System" can figure out what I mean when I ask for:
显然,这实际上创建了一个一维指针数组,指向一堆单独的一维整数数组,当我要求时,“系统”可以弄清楚我的意思:
someNumbers[4][2];
But when I statically declare a 2D array, as in the following line...:
但是当我静态声明一个二维数组时,如下行...:
int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];
...does a similar structure get created on the stack, or is it of another form completely? (i.e. is it a 1D array of pointers? If not, what is it, and how do references to it get figured out?)
...是否在堆栈上创建了类似的结构,还是完全采用另一种形式?(即它是一维指针数组吗?如果不是,它是什么,以及如何找出对它的引用?)
Also, when I said, "The System," what is actually responsible for figuring that out? The kernel? Or does the C compiler sort it out while compiling?
另外,当我说“系统”时,究竟是什么负责解决这个问题?内核?还是 C 编译器在编译时将其整理出来?
采纳答案by Carl Norum
A static two-dimensional array looks like an array of arrays - it's just laid out contiguously in memory. Arrays are not the same thing as pointers, but because you can often use them pretty much interchangeably it can get confusing sometimes. The compiler keeps track properly, though, which makes everything line up nicely. You do have to be careful with static 2D arrays like you mention, since if you try to pass one to a function taking an int **parameter, bad things are going to happen. Here's a quick example:
静态二维数组看起来像一个数组数组——它只是在内存中连续排列。数组与指针不是一回事,但因为你经常可以互换使用它们,所以有时会让人感到困惑。不过,编译器会正确跟踪,这使得一切都很好。你必须小心你提到的静态 2D 数组,因为如果你试图将一个传递给一个带int **参数的函数,不好的事情就会发生。这是一个快速示例:
int array1[3][2] = {{0, 1}, {2, 3}, {4, 5}};
In memory looks like this:
在内存中看起来像这样:
0 1 2 3 4 5
exactlythe same as:
完全一样:
int array2[6] = { 0, 1, 2, 3, 4, 5 };
But if you try to pass array1to this function:
但是如果你尝试传递array1给这个函数:
void function1(int **a);
you'll get a warning (and the app will fail to access the array correctly):
您将收到警告(应用程序将无法正确访问数组):
warning: passing argument 1 of ‘function1' from incompatible pointer type
Because a 2D array is not the same as int **. The automatic decaying of an array into a pointer only goes "one level deep" so to speak. You need to declare the function as:
因为二维数组与int **. 可以这么说,数组自动衰减为指针只会进入“一级深度”。您需要将函数声明为:
void function2(int a[][2]);
or
或者
void function2(int a[3][2]);
To make everything happy.
为了让一切都快乐。
This same concept extends to n-dimensional arrays. Taking advantage of this kind of funny business in your application generally only makes it harder to understand, though. So be careful out there.
这个相同的概念扩展到n维数组。但是,在您的应用程序中利用这种有趣的业务通常只会使其更难理解。所以在外面要小心。
回答by caf
The answer is based on the idea that C doesn't really have2D arrays - it has arrays-of-arrays. When you declare this:
答案是基于这样的思想:C不真的有二维数组-它有数组-的阵列。当你声明这一点时:
int someNumbers[4][2];
You are asking for someNumbersto be an array of 4 elements, where each element of that array is of type int [2](which is itself an array of 2 ints).
您要求someNumbers是一个包含 4 个元素的数组,其中该数组的每个元素都是类型int [2](它本身就是一个 2 个数组int)。
The other part of the puzzle is that arrays are always laid out contiguously in memory. If you ask for:
难题的另一部分是数组总是在内存中连续排列。如果您要求:
sometype_t array[4];
then that will always look like this:
那么它总是看起来像这样:
| sometype_t | sometype_t | sometype_t | sometype_t |
(4 sometype_tobjects laid out next to each other, with no spaces in between). So in your someNumbersarray-of-arrays, it'll look like this:
(4 个sometype_t对象并排放置,中间没有空格)。所以在你的someNumbers数组数组中,它看起来像这样:
| int [2] | int [2] | int [2] | int [2] |
And each int [2]element is itself an array, that looks like this:
每个int [2]元素本身就是一个数组,如下所示:
| int | int |
So overall, you get this:
所以总的来说,你会得到这个:
| int | int | int | int | int | int | int | int |
回答by kanghai
unsigned char MultiArray[5][2]={{0,1},{2,3},{4,5},{6,7},{8,9}};
in memory is equal to:
在内存中等于:
unsigned char SingleArray[10]={0,1,2,3,4,5,6,7,8,9};
回答by Jon L
In answer to your also: Both, though the compiler is doing most of the heavy lifting.
回答您的问题:两者都是,尽管编译器正在完成大部分繁重的工作。
In the case of statically allocated arrays, "The System" will be the compiler. It will reserve the memory like it would for any stack variable.
对于静态分配的数组,“系统”将是编译器。它将像为任何堆栈变量一样保留内存。
In the case of the malloc'd array, "The System" will be the implementer of malloc (the kernel usually). All the compiler will allocate is the base pointer.
在 malloc 数组的情况下,“系统”将是 malloc 的实现者(通常是内核)。编译器将分配的只是基指针。
The compiler is always going to handle the type as what they are declared to be except in the example Carl gave where it can figure out interchangeable usage. This is why if you pass in a [][] to a function it must assume that it is a statically allocated flat, where ** is assumed to be pointer to pointer.
编译器总是按照声明的方式处理类型,除非在 Carl 给出的例子中它可以找出可互换的用法。这就是为什么如果您将 [][] 传递给函数,它必须假定它是静态分配的平面,其中 ** 假定为指向指针的指针。
回答by sqr163
Suppose, we have a1and a2defined and initialized like below (c99):
假设,我们有a1和a2定义和初始化像下面(C99):
int a1[2][2] = {{142,143}, {144,145}};
int **a2 = (int* []){ (int []){242,243}, (int []){244,245} };
a1is a homogeneous 2D array with plain continuous layout in memory and expression (int*)a1is evaluated to a pointer to its first element:
a1是一个在内存中具有简单连续布局的同构 2D 数组,表达式(int*)a1被计算为指向其第一个元素的指针:
a1 --> 142 143 144 145
a2is initialized from a heterogeneous 2D array and is a pointer to a value of type int*, i.e. dereference expression *a2evaluates into a value of type int*, memory layout does not have to be continuous:
a2从异构二维数组初始化,并且是指向 type 值的指针int*,即解引用表达式*a2计算为 type 值int*,内存布局不必是连续的:
a2 --> p1 p2
...
p1 --> 242 243
...
p2 --> 244 245
Despite totally different memory layout and access semantics, C-language grammar for array-access expressions looks exactly the same for both homogeneous and heterogeneous 2D array:
尽管内存布局和访问语义完全不同,数组访问表达式的 C 语言语法对于同构和异构二维数组看起来完全相同:
- expression
a1[1][0]will fetch value144out ofa1array - expression
a2[1][0]will fetch value244out ofa2array
- 表达
a1[1][0]将获取值144出来的a1阵列 - 表达
a2[1][0]将获取值244出来的a2阵列
Compiler knows that the access-expression for a1operates on type int[2][2], when the access-expression for a2operates on type int**. The generated assembly code will follow the homogeneous or heterogeneous access semantics.
编译器知道所述接入表达为a1上式操作int[2][2],当接入表达为a2上式进行操作int**。生成的汇编代码将遵循同构或异构访问语义。
The code usually crashes at run-time when array of type int[N][M]is type-casted and then accessed as type int**, for example:
当 typeint[N][M]类型的数组被类型转换然后作为 type 访问时,代码通常会在运行时崩溃int**,例如:
((int**)a1)[1][0] //crash on dereference of a value of type 'int'
回答by AlphaGoku
To access a particular 2D array consider the memory map for an array declaration as shown in code below:
要访问特定的 2D 数组,请考虑数组声明的内存映射,如下面的代码所示:
0 1
a[0]0 1
a[1]2 3
To access each element, its sufficient to just pass which array you are interested in as parameters to the function. Then use offset for column to access each element individually.
要访问每个元素,只需将您感兴趣的数组作为参数传递给函数就足够了。然后使用 offset for column 单独访问每个元素。
int a[2][2] ={{0,1},{2,3}};
void f1(int *ptr);
void f1(int *ptr)
{
int a=0;
int b=0;
a=ptr[0];
b=ptr[1];
printf("%d\n",a);
printf("%d\n",b);
}
int main()
{
f1(a[0]);
f1(a[1]);
return 0;
}

