Действительно ли имя массива является указателем?

Относительно amcharts, существует "бесплатная" версия с очень немногими ограничениями, которая генерирует диаграммы Flash включая 'диаграмму amCharts.com' упоминание.

И существует хороший плагин, прогулка , который предоставляет Вам некоторые вспомогательные методы легко добавить диаграммы к Вашим представлениям. Обратите внимание на то, что справочная документация amCharts.com - все еще необходимость для адаптации диаграммы в соответствии с требованиями.

191
задан Lundin 21 May 2017 в 22:30
поделиться

6 ответов

Массив - это массив, а указатель - это указатель, но в большинстве случаев имена массивов преобразуются в указатели. Часто используется термин, что они распадаются на указатели.

Вот массив:

int a[7];

a содержит пространство для семи целых чисел, и вы можете поместить значение в одно из них с помощью присваивание, например:

a[3] = 9;

Вот указатель:

int *p;

p не содержит пробелов для целых чисел, но может указывать на пробел для целого числа. Мы можем, например, установить его так, чтобы он указывал на одно из мест в массиве a , например, на первое:

p = &a[0];

Что может сбивать с толку, так это то, что вы также можете написать это:

p = a;

Это не копирует содержимое массива a в указатель p (что бы это ни значило). Вместо, имя массива a преобразуется в указатель на его первый элемент. Таким образом, это присвоение делает то же самое, что и предыдущее.

Теперь вы можете использовать p аналогично массиву:

p[3] = 17;

Причина, по которой это работает, заключается в том, что оператор разыменования массива в C, [] определяется в терминах указателей. x [y] означает: начать с указателя x , шаг y элементов вперед после того, на что указывает указатель, а затем взять все, что там есть. Используя синтаксис арифметики указателей, x [y] также можно записать как * (x + y) .

Для того, чтобы это работало с обычным массивом, таким как наш ] a , имя a в a [3] необходимо сначала преобразовать в указатель (на первый элемент в a ). Затем мы продвигаемся вперед на 3 элемента и берем все, что есть. Другими словами: возьмите элемент в позиции 3 в массиве. (Это четвертый элемент в массиве, поскольку первый имеет номер 0.)

Итак, вкратце, имена массивов в программе на C (в большинстве случаев) преобразуются в указатели. Одно исключение - когда мы используем оператор sizeof в массиве. Если a было преобразовано в указатель в этом контексте, sizeof даст размер указателя, а не фактического массива, что было бы бесполезно, поэтому в этом случае a означает сам массив.

Имена массивов в программе на C (в большинстве случаев) преобразуются в указатели. Одно исключение - когда мы используем оператор sizeof в массиве. Если a было преобразовано в указатель в этом контексте, sizeof даст размер указателя, а не фактического массива, что было бы бесполезно, поэтому в этом случае a означает сам массив.

Имена массивов в программе на C (в большинстве случаев) преобразуются в указатели. Одно исключение - когда мы используем оператор sizeof в массиве. Если a было преобразовано в указатель в этом контексте, sizeof даст размер указателя, а не фактического массива, что было бы бесполезно, поэтому в этом случае a означает сам массив.

235
ответ дан 23 November 2019 в 05:34
поделиться

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

int arr[7];

/* arr used as value */
foo(arr);
int x = *(arr + 1); /* same as arr[1] */

/* arr not used as value */
size_t bytes = sizeof arr;
void *q = &arr; /* void pointers are compatible with pointers to any object */
33
ответ дан 23 November 2019 в 05:34
поделиться

Имя массива само по себе дает место в памяти, поэтому вы можете рассматривать имя массива как указатель:

int a[7];

a[0] = 1976;
a[1] = 1984;

printf("memory location of a: %p", a);

printf("value at memory location %p is %d", a, *a);

И другие изящные вещи, которые вы можете сделать с указателем (например, добавление / вычитание смещения ), вы также можете сделать с массивом:

printf("value at memory location %p is %d", a + 1, *(a + 1));

С точки зрения языка, если C не раскрыл массив как просто некий «указатель» (педантично это просто место в памяти. Он не может указывать в произвольное место в памяти и не может управляться программистом). Нам всегда нужно кодировать это:

printf("value at memory location %p is %d", &a[1], a[1]);
4
ответ дан 23 November 2019 в 05:34
поделиться

Если выражение типа массива (например, имя массива) появляется в более крупном выражении и не является операндом для & или sizeof , то тип выражения массива преобразуется из «N-элементный массив T» в «указатель на T», а значение выражения является адресом первого элемента в массиве.

Короче говоря, имя массива не является указателем, но в большинстве случаев оно обрабатывается , как если бы было указателем.

Edit

Отвечая на вопрос в комментарии:

Если я использую sizeof, подсчитываю ли я размер только элементов массива? Тогда массив «head» также занимает место с информацией о длине и указателе (а это значит, что он занимает больше места, чем обычный указатель)?

Когда вы создаете массив, единственное выделяемое пространство - это пространство для самих элементов; не материализуется хранилище для отдельного указателя или каких-либо метаданных. Учитывая

char a[10];

, вы получаете в памяти

   +---+
a: |   | a[0]
   +---+ 
   |   | a[1]
   +---+
   |   | a[2]
   +---+
    ...
   +---+
   |   | a[9]
   +---+

выражение a относится ко всему массиву, но нет объекта a , отдельного от элементов массива самих себя. Таким образом, sizeof a дает вам размер (в байтах) всего массива. Выражение & a дает вам адрес массива , который совпадает с адресом первого элемента . Разница между и и & a [0] - это тип результата 1 - char (*) [10] в первом случае и char * во втором .

Что странно, так это когда вы хотите получить доступ к отдельным элементам - выражение a [i] определяется как результат * (a + i) - с заданным адресом значение a , смещение i элементов ( не байтов ) от этого адреса и разыменовать результат.

Проблема в том, что a не указатель или адрес - это весь объект массива. Таким образом, правило в C, что всякий раз, когда компилятор видит выражение типа массива (например, a , которое имеет тип char [10] ) и это выражение разве t операнд оператора sizeof или унарного и , тип этого выражения преобразуется («распадается») в тип указателя ( char * ), а значение выражения - это адрес первого элемента массива. Следовательно, выражение a имеет тот же тип и значение, что и выражение & a [0] (и, в более широком смысле, выражение * a имеет тот же тип и значение, что и выражение a [0] ).

C был получен из более раннего языка B, а в B a был отдельным объектом-указателем от элементов массива a [0] , a [1] и т. Д. Ричи хотел сохранить семантику массива B, но не хотел возиться с хранением отдельного объекта-указателя. Итак, он избавился от этого. Вместо этого компилятор при необходимости преобразует выражения массива в выражения указателя во время трансляции.

Помните, я сказал, что массивы не хранят никаких метаданных о своем размере. Как только это выражение массива «распадается» на указатель, все, что у вас есть, - это указатель на единственный элемент. Этот элемент может быть первым из последовательности элементов или может быть отдельным объектом. Невозможно узнать на основе самого указателя.

Когда вы передаете выражение массива функции, все, что она получает, - это указатель на первый элемент - она ​​не знает, насколько велик массив (вот почему функция получает была такой угроза и в конечном итоге был удален из библиотеки). Чтобы функция знала, сколько элементов имеет массив, вы должны либо использовать контрольное значение (например, терминатор 0 в строках C), либо вы должны передать количество элементов как отдельный параметр.


  1. Что * может * повлиять на интерпретацию значения адреса - зависит от машины.
17
ответ дан 23 November 2019 в 05:34
поделиться

Массив, объявленный как этот

int a[10];

, выделяет память для 10 int s. Вы не можете изменить a , но вы можете выполнять арифметические операции с указателями с помощью a .

Такой указатель выделяет память только для указателя p :

int *p;

Он не выделяет никаких int сек. Вы можете изменить его:

p = a;

и использовать индексы массива, как и в случае с:

p[2] = 5;
a[2] = 5;    // same
*(p+2) = 5;  // same effect
*(a+2) = 5;  // same effect
5
ответ дан 23 November 2019 в 05:34
поделиться

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

Разница с переменными-указателями заключается в том, что вы не можете изменить местоположение, на которое указывает имя массива, поэтому он похож на константный указатель (он похож, не то же самое (см. комментарий Марка). Но также то, что вам не нужно разыменовать имя массива, чтобы получить значение, если вы используете аритметику указателя:

char array = "hello wordl";
char* ptr = array;

char c = array[2]; //array[2] holds the character 'l'
char *c1 = ptr[2]; //ptr[2] holds a memory direction that holds the character 'l'

Так что ответ вроде «да».

-4
ответ дан 23 November 2019 в 05:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: