C 数组在内存中如何表示?

发布于 2024-12-10 20:11:11 字数 1911 浏览 0 评论 0原文

如果你使用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                | 
+---------------------+-------------+----------+----------------------+

这是否接近发生的情况,还是完全偏离?

I believe I understand how normal variables and pointers are represented in memory if you are using C.

For example, it's easy to understand that a pointer Ptr will have an address, and its value will be a different address, which is the space in memory it's pointing to. The following code:

int main(){
    int x = 10;
    int *Ptr;
    Ptr = &x;
return 0;
}

Would have the following representation in memory:

+---------------------+-------------+---------+
| Variable Name       | Address     | Value   | 
+---------------------+-------------+---------+
| x                   | 3342        | 10      |
+---------------------+-------------+---------+
| Ptr                 | 5466        | 3342    |
+---------------------+-------------+---------+

However I find it difficult to understand how arrays are represented in memory. For example the code:

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;
}

outputs the same address twice (for the sake of simplicity 10568). Meaning that x==&x. Yet *x (or x[0] in array notation) is equal to 12, *(x+1) (or x[1] in array notation) is equal to 13 and so on. How can this be represented? One way could be this:

+---------------------+-------------+----------+----------------------+
| Variable Name       | Address     | Value    | Value IF array       |
+---------------------+-------------+----------+----------------------+
| x                   | 10568       | 10568    | 12                   |
+---------------------+-------------+----------+----------------------+
|                     | 10572       |          | 13                   | 
+---------------------+-------------+----------+----------------------+
|                     | 10576       |          | 14                   | 
+---------------------+-------------+----------+----------------------+
|                     | 10580       |          | trash                | 
+---------------------+-------------+----------+----------------------+
|                     | 10584       |          | trash                | 
+---------------------+-------------+----------+----------------------+

Is this close to what happens, or completely off?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

栩栩如生 2024-12-17 20:11:12

丹尼尔,

这并不难。您已经有了基本的想法,并且数组的内存表示没有太大区别。如果你声明一个数组,就说

     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]);
    } 

您将看到每个地址以四为间隔递增。(如果您的整数是 32 位长)。
这样你就可以很容易地理解数组是如何存储在内存中的。

您也可以使用不同的方法尝试同样的事情。

    int i;
    for(i=0;i<5;i++){
       printf("location of %d is %d\n",*(a+i),a+i);
    }

在这两种情况下你都会得到相同的答案,并尝试获得等价的答案。

使用不同的数据类型(char、float 和 struct 类型)尝试相同的实验。您将看到相邻元素之间的间隙如何根据单个元素的大小而变化。

Daniel,

this is not difficult. You have the basic idea and there's no much difference in memory representation of arrays. if you declare an array, say

     void main(){
         int arr[5]={0,1,2,3,4};


     }

you have initialized(defined) the array. So the five elements will be stored in five adjacent locations in memory. you can observe this by referencing the memory address of each element.
Not like other primitive data types in C, an array identifier(here, arr) itself represents its pointer. The idea seems vague if you are a beginner but you will feel comfortable as you go on.

      printf("%d",arr);

this line will show you the memory address of the first element, arr[0]. This is similar to referencing the address of the first element.

      printf("%d",&arr[0]);

now, you can view memory locations of all elements. The following piece of code will do the job.

    int i;
    for(i=0;i<5;i++){
       printf("location of %d is %d\n",arr[i],&arr[i]);
    } 

you will see each address increments by gaps of four.(if your integers are 32 bits long).
So you can easily understand how the arrays are stored in the memory.

you can also try the same thing using a different method.

    int i;
    for(i=0;i<5;i++){
       printf("location of %d is %d\n",*(a+i),a+i);
    }

you will get the same set of answers in both cases and try to get the equivalence.

try the same experiment using different data types(char, float and struct types). You will see how the gaps between adjacent elements vary based on the size of a single element.

月下客 2024-12-17 20:11:12

int x[] 产生与 int* x 相同的结果;

它只是一个指针

因此符号 x[i] 和 *(x + i) 产生相同的结果。

int x[] produces the same result as int* x;

it's just a pointer

therefore notations x[i] and *(x + i) produce the same result.

情定在深秋 2024-12-17 20:11:11

数组是一组连续的对象,对象之间没有空格。这意味着第二个示例中的 x 在内存中表示为:

+---------------------+-------------+---------+
| Variable Name       | Address     | Value   | 
+---------------------+-------------+---------+
| x                   | 10568       | 12      |
|                     |             +---------+
|                     |             | 13      |
|                     |             +---------+
|                     |             | 14      |
|                     |             +---------+
|                     |             | ??      |
|                     |             +---------+
|                     |             | ??      |
+---------------------+-------------+---------+

也就是说,x 有 5 个 int 大,并且有一个地址。

数组的奇怪之处不在于它们的存储方式,而在于它们在表达式中的求值方式。如果您在某处使用的数组名称不是一元 &sizeof 运算符的主题,则它将计算为其第一个成员的地址。

也就是说,如果你只写x,你将得到一个int *类型的值10568。

另一方面,如果您编写 &x,则特殊规则不适用 - 因此 & 运算符的工作方式与通常一样,这意味着它获取数组的地址。在示例中,该值为 int (*)[5] 类型的值 10568。

x == &x 的原因是数组的第一个成员的地址必然等于数组本身的地址,因为数组从其第一个成员开始。

An array is a block of contiguous objects with no spaces in between. This means that x in your second example is represented in memory as:

+---------------------+-------------+---------+
| Variable Name       | Address     | Value   | 
+---------------------+-------------+---------+
| x                   | 10568       | 12      |
|                     |             +---------+
|                     |             | 13      |
|                     |             +---------+
|                     |             | 14      |
|                     |             +---------+
|                     |             | ??      |
|                     |             +---------+
|                     |             | ??      |
+---------------------+-------------+---------+

That is, x is five ints big, and has a single address.

The weird part about arrays isn't in how they're stored - it's how they're evaluated in expressions. If you use an array name somewhere that it isn't the subject of the unary & or sizeof operators, it evaluates to the address of its first member.

That is, if you just write x, you will get a value 10568 with type int *.

If, on the other hand you write &x, then the special rule doesn't apply - so the & operator works like it normally does, which means that it fetches the address of the array. In the example, this will be a value 10568 with type int (*)[5].

The reason that x == &x is that the address of the first member of an array is necessarily equal to the address of the array itself, since an array starts with its first member.

静水深流 2024-12-17 20:11:11

你的图表是正确的。 &x 周围的奇怪之处与数组在内存中的表示方式无关。它与数组->指针衰减有关。 x 本身在值上下文中衰减为指向其第一个元素的指针;即,它相当于&x[0]&x 是一个指向数组的指针,两者在数值上相等只是说数组的地址在数值上等于其第一个元素的地址。

Your diagram is correct. The weirdness around &x has nothing to do with how arrays are represented in memory. It has to do with array->pointer decay. x by itself in value context decays into a pointer to its first element; i.e., it is equivalent to &x[0]. &x is a pointer to an array, and the fact that the two are numerically equal is just saying that the address of an array is numerically equal to the address of its first element.

呆° 2024-12-17 20:11:11

是的,你已经明白了。 AC 数组通过计算x + (y * sizeof(type)) 找到索引值x[y]x 是数组的起始地址。 y * sizeof(type) 是相对于此的偏移量。 x[0] 生成与 x 相同的地址。

多维数组的处理方式类似,因此 int x[y][z] 将消耗 sizeof(int) * y * z 内存。

因此你可以做一些愚蠢的 C 指针技巧。这也意味着获取数组的大小(几乎)是不可能的。

Yes, you've got it. A C array finds the indexed value x[y] by calculating x + (y * sizeof(type)). x is the starting address of the array. y * sizeof(type) is an offset from that. x[0] produces the same address as x.

Multidimensional arrays are similarly done, so int x[y][z] is going to consume sizeof(int) * y * z memory.

Because of this you can do some stupid C pointer tricks. It also means getting the size of an array is (almost) impossible.

谜兔 2024-12-17 20:11:11

C 中的数组是一个连续的内存块,每个成员的块大小相同。这就是指针起作用的原因,您根据第一个成员的地址寻找偏移量。

An array in C is a sequential block of memory with each member's block of the same size. This is why pointers work, you seek an offset based on the first member's address.

聊慰 2024-12-17 20:11:11

C 常见问题解答中的数组和指针部分提供了一些有用的信息。

The Arrays and Pointers section in the C FAQ has some helpful information.

无畏 2024-12-17 20:11:11

AC 数组只是一个具有相同大小的连续值的内存块。当您调用 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

A C array is just a block of memory that has sequential values of the same size. When you call malloc(), it is just granting you a block of memory. foo[5] is the same as *(foo + 5).

Example - 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);
}

Output:

$ ./foo
&foo[0]: 5fbff5a4
foo: 5fbff5a4

&foo[3]: 5fbff5b0
foo: 5fbff5b0
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文