Член структуры [массив против указателя] - PullRequest
3 голосов
/ 10 апреля 2010

В чем преимущество объявления члена структуры C в виде массива размера 1 вместо указателя:

struct {
  a_struct_t a_member[1];
  ...
}b_struct;

Заранее спасибо

Ответы [ 5 ]

5 голосов
/ 10 апреля 2010

В типичном случае структура с элементом, объявленным как массив из одного элемента, будет иметь этот элемент в качестве элемента last в структуре. Предполагается, что структура будет размещена динамически. Когда он выделен, код выделит пространство для такого количества элементов, которое вам действительно нужно / нужно в этом массиве:

struct X {
    time_t birthday;
    char name[1];
};

struct X *x = malloc(sizeof(*x) + 35);
x->birthday = mktime(&t);
strcpy(x->name, "no more than 35 characters");

Это особенно хорошо работает со строками - символ, который вы выделяете в структуре, дает вам место для терминатора NUL, поэтому, когда вы делаете выделение, количество символов, которое вы выделяете, в точности равно strlen() строки ты собираешься поставить там. Для большинства других типов элементов вы обычно хотите вычесть один из размера выделения (или просто жить с выделенным пространством, которое на один элемент больше, чем это строго необходимо).

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

2 голосов
/ 10 апреля 2010

То, что вы описываете, совершенно разные вещи. Если у вас есть указатель в качестве члена:

a_struct_t* a_member;

тогда это просто указатель. Внутри структуры не выделена память для хранения a_struct_t. Если, с другой стороны, у вас есть массив размером 1:

a_struct_t a_member[1];

тогда ваша структура на самом деле содержит объект типа a_struct_t внутри. С точки зрения памяти, это мало чем отличается от простого помещения объекта такого типа в структуру:

a_struct_t a_member;

С точки зрения использования массив требует косвенного доступа для доступа к одному элементу (т. Е. Вам нужно использовать *a_member вместо a_member).

2 голосов
/ 10 апреля 2010

"Массив размера 1 вместо указателя"? Извините, но я не понимаю, как этот вопрос может иметь смысл. Я бы понял, если бы вы спросили о «массиве размера 1 вместо обычного члена (не массива)». Но "вместо указателя"? При чем здесь указатель? Как это взаимозаменяемо с массивом, чтобы оправдать вопрос?

Если вы действительно хотели спросить, почему он объявлен как массив размера 1, а не как массив, как в

struct { 
  a_struct_t a_member; 
} b_struct; 

тогда одним из возможных объяснений является хорошо известная идиома, называемая "struct hack". Вы можете увидеть объявление вроде

struct { 
  ...
  a_struct_t a_member[1]; 
} b_struct; 

используется для реализации массива гибкого размера в качестве последнего члена объекта структуры. Фактический объект структуры позже создается в блоке памяти, который достаточно большой, чтобы вместить столько элементов массива, сколько необходимо. Но в этом случае массив должен быть последним членом структуры, а не первым, как в вашем примере.

P.S. Время от времени вы можете видеть, как «взлом структуры» реализуется через массив размера 0, что на самом деле является нарушением ограничения в C (то есть ошибка компиляции).

0 голосов
/ 10 апреля 2010

Так что я думаю, что было заявлено, что основное различие между указателями и массивами состоит в том, что вы должны выделять память для указателей.

Сложность вашего вопроса в том, что даже когда вы выделяете пространство для своей структуры, если ваша структура содержит указатель, вы должны выделить ВТОРОЕ время для указателя, но сам указатель будет выделен как часть выделения структуры .

Если бы ваша структура содержала массив 1, вам не пришлось бы выделять какую-либо дополнительную память, она сохранялась бы в структуре (которую вам еще нужно выделить).

0 голосов
/ 10 апреля 2010

Это разные вещи.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...