Причина выбора массива из одного элемента вместо одного объекта? - PullRequest
0 голосов
/ 18 января 2020

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

Например, fe

int a[1] = {10};

вместо

int a = 10;

Конечно, существует большая разница в контексте доступа к значению 10 в последующем коде между обоими случаями, используя a:

  1. Когда a объявлен как массив, как
int a[1] = {10};

a распадается на указатель на первый элемент элемента массива a, поэтому a соответствует типу int*, когда a используется позже в программе.

Когда a объявлен в качестве идентификатора определенного объекта, например,
int a = 10;

a имеет тип int.

Если мы хотим чтобы передать значение 10 функции, мы должны обратить на это внимание и должны различать guish между обоими вариантами использования.

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


  • Есть ли места в C и / или C ++, где нужен массив вместо одного объекта?
  • Существуют ли физические различия в размере выделения в памяти?
  • Отличаются ли C и C ++ в этом контексте?
  • Есть ли причина для выбора массив одного элемента вместо одного объекта?

Причина пометки тегами C и C ++: я пометил его обоими языковыми тегами, потому что оба оператора действительны в C и C ++, и в настоящий момент я не не знаю никакой разницы между обоими языками в этом случае. Если есть разница, пожалуйста, учтите.

Спасибо за вашу помощь.

Ответы [ 6 ]

2 голосов
/ 18 января 2020

По моему мнению, нет смысла объявлять массив для одного объекта. Я настоятельно рекомендую использовать Basi c: a = 10 ;

1 голос
/ 18 января 2020

Иногда функция, написанная для общего случая, будет означать получение массива, например, в C у вас может быть что-то вроде:

#define CULL_OBJECTS(objs) {\ 
           for(int i = 0; i < sizeof(objs)/sizeof(objs[0]); ++i)\ 
           {\ 
                ++culled_objects;\ 
                cull_subobjects(objs[i]);\ 
           }\

или в C ++:

template<typename T>
void CullObjects(T& objs)
{
    for(int i = 0; i < sizeof(objs)/sizeof(objs[0]); ++i)
    {
        ++culled_objects;
        cull_subobjects(objs[i]);
    }
}

Который может быть вызван путем передачи Obj objArr[1000] или Obj obj[1].

1 голос
/ 18 января 2020

Есть ли в C и / или C ++ места, где требуется массив вместо одного объекта?

Почему я использую массив из одного элемента вместо одного объекта? ?

Есть много функций, которые могут работать с массивами, которые принимают аргумент указателя. Однако, как уже указывал machine_1, вы можете легко получить указатель на обычный объект и передать его функции.

Однако есть несколько случаев, когда это имеет значение. В C ++, если вы хотите использовать range-for для итерации по нескольким объектам, вы можете написать:

int a[1] = {42};
for (auto &value: a)
     ...

Но вы не можете написать:

int a = 42;
for (auto &value: a)
     ...

Приведенный выше пример выглядит глупо сам по себе, но становится реальной проблемой, когда вы определяете функции generi c с помощью шаблонов. Поэтому иногда вам захочется сохранить значение в массиве длиной 1, чтобы упростить использование этих функций.

В C99 и более поздних версиях, но не в C ++, вы также можете использовать Flexible члены массива . Такие члены работают как массивы, но они не занимают места, как будто они имеют нулевую длину. Рассмотрим наличие сетевого пакета с заголовком и переменным объемом данных. Структура, представляющая пакет, может выглядеть следующим образом:

struct packet {
    address_t source;
    address_t destination;
    size_t length;
    char data[]; // flexible array member
};

Можно выделить память для такой структуры, например, так:

size_t data_length;
...
struct packet *pkt = malloc(sizeof(*pkt) + data_length);

А затем можно читать и записывать в часть данных вот так:

for (size_t i = 0; i < data_length; i++)
     pkt->data[i] = ...;

Вам не нужен массив data[] здесь, поскольку вы также можете получить доступ к данным, выполнив что-то вроде ((char *)pkt + sizeof(*pkt))[i], использование члена массива в конце структуры позволяет написание гораздо более компактного, удобочитаемого и безопасного кода.

Можно сделать аналогичный трюк в C ++ , используя массив длиной 1.

Is Есть физическая разница в размере выделения в памяти?

Нет.

Различаются ли C и C ++ в этом контексте?

номер

1 голос
/ 18 января 2020

Есть ли в C и / или C ++ места, где нужен массив вместо одного объекта?

Я думаю, вы в основном встретите C - массив стилей с одним объектом в качестве конца рекурсивной функции для одного объекта. Если у вас есть функция, которая принимает массив C -подобным образом (f(int* array, int length)), вы можете использовать ее для применения функции только к одному входу без дополнительной перегрузки. Но вы можете сделать то же самое с int a = 42; f(&a, 1);.

Существуют ли физические различия в размере выделения в памяти?

Нет. int a[1] = {42} и int a = 42 делают то же самое со стеком.

Отличаются ли C и C ++ в этом контексте?

Нет.

Почему я использую массив из одного элемента вместо одного объекта?

Массив с размером компиляции 1 (как вы делали выше), вероятно, использовал очень мало. Существует разница между

int a[1] = {42};
// and
int b = 42;
int *a = &b;

, поскольку массив не является указателем, а только распадается на единицу. Но разница в при использовании их очень незначительна. Наиболее заметное различие в их использовании (thx @Scheff) должно заключаться в том, что вы можете использовать std::begin(a) и std::end(a) на int a[1], но не на int *a. Это только разница в C ++. Обратите внимание, что это исчезает, когда массив распался на указатель. Затем вы заменяете их на a и a+1 соответственно.

Я мог бы представить, что вы делаете int a[1] = {42};, если хотите инициализировать объект в стеке и иметь прямой указатель на него (и на самом деле не использовать само значение), так как оно немного короче. Но я никогда не видел этого сам и на самом деле считаю это плохим стилем. Я думаю, что это было бы очень редко в коде C ++, поскольку сами raw-указатели не так часто встречаются.

На самом деле я чаще видел массив длины 0, см. Здесь использование . Поскольку эти кажутся технически недопустимыми в более старых версиях C, недопустимы в C (спасибо за комментарии), можно использовать массив длины 1, чтобы быть допустимым. Но, насколько мне известно, большинство компиляторов реализовали массивы нулевой длины, так как почти всегда, поэтому большинство людей, вероятно, проигнорируют это и будут использовать массив нулевой длины.

0 голосов
/ 18 января 2020

Нет причин использовать int a[1]; вместо int a;. Используйте &a, чтобы передать указатель на него при необходимости. Другие люди будут очень смущены int a[1];, если вы когда-нибудь напишите это - это будет выглядеть как ошибка.

Тогда вы, вероятно, спросите, зачем это вообще нужно в языке?

Это просто. Скажем, вам нужен фиксированный массив размером N, например, int a[N];, и вы не знаете значение N. Это либо макрос, либо результат вычисления constexpr, либо параметр шаблона. Таким образом, int a[1] необходимо поддерживать для его работы.

0 голосов
/ 18 января 2020

Вы не должны объявлять массив, состоящий из одного объекта. Если вам нужна одна переменная, объявите ее как таковую. Но чтобы ответить на ваш вопрос, можно написать что-то вроде:

int a[1];

, вероятно, для удобства при работе с функциями, которые принимают указатель в качестве аргумента. Возьмем, к примеру, функцию memset(), объявленную как:

void * memset (void *ptr, int value, size_t num );

Если вы объявляете одну переменную и хотите использовать memset() для нее, вы должны вызвать ее как:

int a;
memset(&a, val, sizeof(int));

если вы объявите a как int a[1], то вы бы назвали его следующим образом:

memset(a, val, sizeof(int));

Однако, первое использование - для чего-то странного или необычного!

...