是"阵列"元素值存储在一个位置或不同的位置?

时间:2016-11-01 16:31:30

标签: c arrays pointers memory-layout

由于C语言中没有数组这样的东西,以下所有内容都存储在一个内存位置,或者每个元素的值都存储在"数组中。内存位置?

int array[] = {11, 13, 17, 19};
  • 情景1

    {11, 13, 17, 19} --> location A
    
  • 情景2

    {
        11 --> location A
        13 --> location B
        17 --> location C
        19 --> location D
    }
    

哪一个是有效的内存布局?

5 个答案:

答案 0 :(得分:7)

C明确将“数组”定义为类型。

引用C11,章节§6.2.5,类型(强调我的

  

数组类型描述了一个连续分配的非空对象集   特定的成员对象类型,称为元素类型。元素类型应为   指定数组类型时完成。数组类型的特点是它们的   元素类型和数组中元素的数量。据说是一种数组类型   从其元素类型派生,如果其元素类型为T,则有时是数组类型   称为''T'数组'。调用元素类型的数组类型的构造   ''数组类型推导''。

简而言之,答案是,数组元素存储在不同但相邻的位置。

假设我们已经声明了一个5 int的数组:

int arr[5];

然后,在一个整数大小为2个字节(szeof(int) ==2)的平台上,该数组的元素组织如下:

enter image description here

sizeof(int) == 4的不同平台上,可能是:

enter image description here

所以代表

{
    11 --> location A
    13 --> location B
    17 --> location C
    19 --> location D
}

有效,考虑B == A + 1C == B + 1等。

请注意,指针算法会考虑数据类型,因此A+1不会产生1 byte增量的地址,而是增量为element。换句话说,两个连续元素的地址之间的差异将与数据类型(sizeof (datatype))的大小相同。

答案 1 :(得分:3)

元素将位于连续内存位置。

array[0]位于B位置,数组中每个元素的大小(即sizeof(int))为S.然后我们就有了这个

array[0] at B
array[1] at B + S
array[2] at B + 2S
..
array[n] at B + n*S

答案 2 :(得分:1)

编译器在特定的连续位置分配数组。

您还可以使用下一个代码进行检查:

#include <stdio.h>

void main()
{
    int array[] = {11, 13, 17, 19};
    for (int i = 0; i < 4; i++)
        printf("0x%p ", &array[i]);
}

这给出了十六进制地址

0x14fee0 0x14fee4 0x14fee8 0x14feec

每个元素的边距为4个字节,大小为int。

通常,您可以将指针指向数组的一个元素,例如index m,并将其添加为n作为多个元素,并获取指向n+m的指针数组中的索引。

*(array + n) == array[n]

答案 3 :(得分:1)

C确实有一个数组类型。仅仅因为你可以通过指针访问数组并不意味着它们不存在。

数组元素存储在从地址“array”开始的连续内存位置(即array的基址,也是数组的第一个元素的地址),并且数组的每个元素都是可寻址的分开。

假设4个字节的整数,数组int array[] = {11, 13, 17, 19};看起来像:

+-----+-----+-----+-----+
|  11 |  13 |  17 |  19 |
+-----+-----+-----+-----+
  ^     ^     ^      ^
0x100 0x104  0x108  0x112

您可以通过简单的程序更好地理解:

#include <stdio.h>

int main(void)
{
int array[] = {11, 13, 17, 19};

/* all will print the same value */
printf("Base address of array: %p, %p, %p\n", (void*)array, (void*)&array[0], (void*)array);

for (size_t i = 0; i < sizeof array/sizeof array[0]; i++) {
      printf("address of array[%d]: %p\n", i, (void*)&array[i]);
}

return 0;
}

一个重要的细节是,虽然地址&array[0]&array是相同的值,但它们的类型是不同的。 &array[0]的类型为int*(指向int的指针),而&array的类型为int(*)[4](指向4个整数的数组的指针)。

答案 4 :(得分:0)

  

因为C语言中没有数组这样的东西

在C语言中完全存在数组这样的东西。您的所有示例都是C数组。

您所描述的差异是listarray之间的差异。

C中的数组,就像大多数语言一样,就像你的Scenerio 1。

你当然可以通过一系列指向数值的指针来完成Scenerio 2。例如

int array1[] = {11, 14, 17, 19};
// vs 
int* array2[] = {
    &array1[0],
    &array1[1],
    &array1[2],
    &array1[3]
};

但是list在组织方面有很大不同。

struct list_node{
    int value;
    struct list_node * next;
};

struct int_list {
    int length;
    struct list_node * first;
};

int main(){
    int i;
    struct list_node nodes[4];
    struct int_list list1 = {.length = 4, .first=&nodes[0]};
    for (i = 0; i < 4; i++){
        nodes[i].value = array1[i];
        if (i != 3){
            nodes[i].next = &nodes[i+1];
        } else {
            nodes[i].next = NULL;
        }
    }

    // traverse the list.
    struct list_node * n = list1.first;
    while(n != NULL){
        printf("%d\n", n->value);
        n = n->next;
    }
}