Подтвердить что ты не робот

Как представлены массивы C в памяти?

Я считаю, что понимаю, как обычные переменные и указатели представлены в памяти, если вы используете 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                | 
+---------------------+-------------+----------+----------------------+

Это близко к тому, что происходит или полностью отключено?

4b9b3361

Ответ 1

Массив - это блок смежных объектов без пробелов между ними. Это означает, что x в вашем втором примере представлен в памяти как:

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

То есть, x имеет пять int больших и имеет один адрес.

Странная часть массивов заключается не в том, как они хранятся, а в том, как они оцениваются в выражениях. Если вы где-то используете имя массива, это не относится к унарным операторам & или sizeof, он оценивает адрес своего первого члена.

То есть, если вы просто напишете x, вы получите значение 10568 с типом int *.

Если, с другой стороны, вы пишете &x, тогда специальное правило не применяется, поэтому оператор & работает так, как обычно, это означает, что он выбирает адрес массива. В этом примере это будет значение 10568 с типом int (*)[5].

Причина, по которой x == &x заключается в том, что адрес первого элемента массива обязательно равен адресу самого массива, так как массив начинается с его первого члена.

Ответ 2

Ваша диаграмма верна. Странность вокруг &x не имеет ничего общего с тем, как массивы представлены в памяти. Это связано с распадом указателя array- > . x сам по себе в контексте значений распадается на указатель на его первый элемент; т.е. он эквивалентен &x[0]. &x является указателем на массив, а тот факт, что эти два являются численно равными, просто говорит, что адрес массива численно равен адресу его первого элемента.

Ответ 3

Да, у тебя это есть. Массив C находит индексированное значение x[y], вычисляя x + (y * sizeof(type)). x - начальный адрес массива. y * sizeof(type) является смещением от этого. x[0] создает тот же адрес, что и x.

Аналогично выполняются многомерные массивы, поэтому int x[y][z] будет потреблять память sizeof(int) * y * z.

Из-за этого вы можете делать какие-то глупые трюки с указателем на C. Это также означает, что получение размера массива (почти) невозможно.

Ответ 4

Массив 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

Ответ 5

Массив в C является последовательным блоком памяти с каждым блоком-членом того же размера. Вот почему указатели работают, вы ищете смещение на основе первого адреса элемента.

Ответ 7

Даниил,

это не сложно. У вас есть основная идея, и нет большой разницы в представлении массивов в памяти. если вы объявите массив, скажите

     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 types). Вы увидите, как промежутки между соседними элементами изменяются в зависимости от размера одного элемента.

Ответ 8

int x [] производит тот же результат, что и int * x;

это просто указатель

поэтому обозначения x [i] и * (x + i) дают тот же результат.