我相信如果你使用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 |
+---------------------+-------------+----------+----------------------+
这接近发生的事情,还是完全关闭?
答案 0 :(得分:33)
数组是一个连续对象块,中间没有空格。这意味着第二个示例中的x
在内存中表示为:
+---------------------+-------------+---------+
| Variable Name | Address | Value |
+---------------------+-------------+---------+
| x | 10568 | 12 |
| | +---------+
| | | 13 |
| | +---------+
| | | 14 |
| | +---------+
| | | ?? |
| | +---------+
| | | ?? |
+---------------------+-------------+---------+
也就是说,x
是五个int
大,并且只有一个地址。
关于数组的奇怪部分不在于它们的存储方式 - 它们是如何在表达式中进行评估的。如果您在某个地方使用的数组名称不是一元&
或sizeof
运算符的主题,那么它将计算其第一个成员的地址。
也就是说,如果你只是写x
,你会得到一个类型为int *
的值为10568。
另一方面,如果您编写&x
,则特殊规则不适用 - 因此&
运算符的工作方式与正常情况相同,这意味着它将获取数组的地址。在示例中,这将是类型为int (*)[5]
的值10568。
x == &x
的原因是数组的第一个成员的地址必须等于数组本身的地址,因为数组以其第一个成员开头。
答案 1 :(得分:22)
您的图表是正确的。 &x
周围的奇怪与数组在内存中的表示方式无关。它与array->指针衰减有关。 x
本身在值上下文中衰减为指向其第一个元素的指针;即,它相当于&x[0]
。 &x
是指向数组的指针,两者在数值上相等的事实只是说数组的地址在数值上等于其第一个元素的地址。
答案 2 :(得分:2)
是的,你已经明白了。 C数组通过计算x[y]
来查找索引值x + (y * sizeof(type))
。 x
是数组的起始地址。 y * sizeof(type)
是对此的偏移。 x[0]
生成与x相同的地址。
多维数组也是类似的,所以int x[y][z]
会消耗sizeof(int) * y * z
个内存。
因此你可以做一些愚蠢的C指针技巧。这也意味着获得数组的大小(几乎)是不可能的。
答案 3 :(得分:0)
C数组只是一块具有相同大小的连续值的内存块。当你调用malloc()时,它只是给你一块内存。 foo[5]
与*(foo + 5)
相同。
示例 - foo.c:
#include <stdio.h>
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
答案 4 :(得分:0)
C中的数组是一个连续的内存块,每个成员的块大小相同。这就是指针工作的原因,你根据第一个成员的地址寻找偏移量。
答案 5 :(得分:0)
答案 6 :(得分:0)
丹尼尔,
这并不困难。你有基本的想法,并且数组的内存表示没有太大区别。如果你声明一个数组,比如说 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类型)尝试相同的实验。您将看到相邻元素之间的间隙如何根据单个元素的大小而变化。
答案 7 :(得分:-1)
int x []产生与int * x;
相同的结果它只是一个指针
因此符号x [i]和*(x + i)产生相同的结果。