如何在内存中代表Carrays?
我相信如果你使用C,我理解在内存中如何表示正常的变量和指针。
例如,很容易理解指针Ptr将具有一个地址,并且它的值将是一个不同的地址,这是它指向的内存空间。 以下代码:
int main(){ int x = 10; int *Ptr; Ptr = &x; return 0; }
将在内存中具有以下表示:
+---------------------+-------------+---------+ | Variable Name | Address | Value | +---------------------+-------------+---------+ | x | 3342 | 10 | +---------------------+-------------+---------+ | Ptr | 5466 | 3342 | +---------------------+-------------+---------+
但是我发现很难理解数组如何在内存中表示。 例如代码:
int main(){ int x[5]; x[0]=12; x[1]=13; x[2]=14; printf("%p\n",(void*)x); printf("%p\n",(void*)&x); return 0; }
输出相同的地址两次(为简单起见10568)。 意思是x ==&x。 然而,* x(或数组符号中的x [0])等于12,*(x + 1)(或数组符号中的x [1])等于13,依此类推。 怎么能代表这个? 一种方法可能是这样的:
+---------------------+-------------+----------+----------------------+ | Variable Name | Address | Value | Value IF array | +---------------------+-------------+----------+----------------------+ | x | 10568 | 10568 | 12 | +---------------------+-------------+----------+----------------------+ | | 10572 | | 13 | +---------------------+-------------+----------+----------------------+ | | 10576 | | 14 | +---------------------+-------------+----------+----------------------+ | | 10580 | | trash | +---------------------+-------------+----------+----------------------+ | | 10584 | | trash | +---------------------+-------------+----------+----------------------+
这接近发生的事情,还是完全关闭?
数组是一个连续对象块,中间没有空格。 这意味着第二个示例中的x
在内存中表示为:
+---------------------+-------------+---------+ | Variable Name | Address | Value | +---------------------+-------------+---------+ | x | 10568 | 12 | | | +---------+ | | | 13 | | | +---------+ | | | 14 | | | +---------+ | | | ?? | | | +---------+ | | | ?? | +---------------------+-------------+---------+
也就是说, x
是五个大的,并且只有一个地址。
关于数组的奇怪部分不在于它们是如何存储的 – 它们是如何在表达式中进行评估的。 如果在某处使用数组名称,它不是一元&
或sizeof
运算符的主题,则它将计算其第一个成员的地址。
也就是说,如果你只是写x
,你会得到一个类型为int *
的值10568。
另一方面,如果你写&x
,那么特殊规则不适用 – 所以&
运算符就像通常那样工作,这意味着它获取数组的地址。 在示例中,这将是值为10568,类型为int (*)[5]
。
x == &x
的原因是数组的第一个成员的地址必须等于数组本身的地址,因为数组以其第一个成员开头。
你的图表是正确的。 围绕&x
的怪异与如何在内存中表示数组无关。 它与array->指针衰减有关。 x
本身在值上下文中衰减为指向其第一个元素的指针; 即,它相当于&x[0]
。 &x
是指向数组的指针,并且两者在数值上相等的事实只是说数组的地址在数值上等于其第一个元素的地址。
是的,你已经明白了。 ACarrays通过计算x + (y * sizeof(type))
找到索引值x[y]
。 x
是数组的起始地址。 y * sizeof(type)
是一个偏移量。 x[0]
产生与x相同的地址。
多维数组类似地完成,因此int x[y][z]
将消耗sizeof(int) * y * z
内存。
因此,你可以做一些愚蠢的C指针技巧。 这也意味着获得数组的大小(几乎)是不可能的。
C中的数组是一个连续的内存块,每个成员的块大小相同。 这就是指针工作的原因,你根据第一个成员的地址寻找偏移量。
C FAQ中的Arrays and Pointers部分提供了一些有用的信息。
AC数组只是一块具有相同大小的连续值的内存块。 当你调用malloc()时,它只是给你一块内存。 foo[5]
与*(foo + 5)
。
示例 – foo.c:
#include int main(void) { int foo[5]; printf("&foo[0]: %tx\n", &foo[0]); printf("foo: %tx\n\n", foo); printf("&foo[3]: %tx\n", &foo[3]); printf("foo: %tx\n", foo + 3); }
输出:
$ ./foo &foo[0]: 5fbff5a4 foo: 5fbff5a4 &foo[3]: 5fbff5b0 foo: 5fbff5b0
丹尼尔,
这并不困难。 你有基本的想法,并且数组的内存表示没有太大区别。 如果你声明一个数组,比如说
void main(){ int arr[5]={0,1,2,3,4}; }
你已经初始化(定义)了数组。 因此,五个元素将存储在内存中的五个相邻位置。 你可以通过引用每个元素的内存地址来观察它。 与C中的其他原始数据类型不同,数组标识符(此处为arr )本身表示其指针。 如果你是一个初学者,这个想法似乎含糊不清,但你会感觉很舒服。
printf("%d",arr);
这一行将显示第一个元素arr [0]的内存地址。 这类似于引用第一个元素的地址。
printf("%d",&arr[0]);
现在,您可以查看所有元素的内存位置。 以下代码将完成这项工作。
int i; for(i=0;i<5;i++){ printf("location of %d is %d\n",arr[i],&arr[i]); }
你将看到每个地址以4的间隙递增。(如果你的整数是32位长)。 因此,您可以轻松了解数组如何存储在内存中。
你也可以尝试使用不同的方法做同样的事情。
int i; for(i=0;i<5;i++){ printf("location of %d is %d\n",*(a+i),a+i); }
在这两种情况下,你都会得到同样的答案,并尝试获得等价。
使用不同的数据类型(char,float和struct类型)尝试相同的实验。 您将看到相邻元素之间的间隙如何根据单个元素的大小而变化。
int x []产生与int * x相同的结果;
它只是一个指针
因此,符号x [i]和*(x + i)产生相同的结果。