Как хранить пользовательские объекты (структуры) в C? - PullRequest
0 голосов
/ 08 мая 2018

Я хочу знать, как хранить пользовательские объекты (не их указатели) в C. Я создал пользовательскую структуру с именем Node

#define MAXQ 100

typedef struct {
  int state[MAXQ];
  int height;
} Node;

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

Интернет, кажется, предлагает что-то вроде calloc(), поэтому моей последней попыткой было сделать контейнер Neighbors, следующий за этому примеру , с numNeighbors, являющимся просто целым числом:

Node Neighbors = (Node*)calloc(numNeighbors, sizeof(Node));

При компиляции я получил ошибку из этой строки, говорящую
initializing 'Node' with an expression of incompatible type 'void *'

и в местах, где я ссылался на этот контейнер (как в Neighbors[i]), я получал ошибки
subscripted value is not an array, pointer, or vector

Так как я испорчен Python, я понятия не имею, правильно ли я понял мой синтаксис (он должен сказать вам кое-что, что я все еще не там, после того, как прочесал тонну учебников, документов и стекопотока malloc(), calloc() и т. П.), Или если я использую совершенно неверный подход к хранению пользовательских объектов (поиск «хранить пользовательские объекты в C» в Интернете дает нерелевантные результаты, касающиеся iOS и C #, поэтому я был бы очень признателен за некоторые помощь).

РЕДАКТИРОВАТЬ: Спасибо за советы всем, он наконец-то скомпилирован без ошибок!

Ответы [ 4 ]

0 голосов
/ 08 мая 2018

Я хочу сохранить несколько таких узлов в контейнере (без использования указателей, поскольку они не хранятся в другом месте), чтобы я мог получить к ним доступ позже.

Если вы знаете их количество во время компиляции (или, по крайней мере, разумный максимум); затем вы можете создать массив объектов, выделенных из стека Например, скажем, у вас все в порядке с максимум 10 объектами:

#define MAX_NODES 10

Node nodes[MAX_NODES];
int number_nodes = 0;

Затем, когда вы добавляете объект, вы синхронизируете number_nodes (чтобы вы знали, куда поместить следующий объект). Технически у вас всегда будет 10, но вы используете только те, которые вам нужны / нужны. Удаление объектов аналогично, но более сложное, если вы хотите убрать его посередине.

Однако, если вы не знаете, сколько у вас будет (ни как максимум); или даже если вы знаете, но их слишком много, чтобы поместиться в стек; тогда вы вынуждены использовать кучу (обычно с malloc() и free()):

int number_nodes; // unknown until runtime or too big
Node * nodes = malloc(sizeof(Node) * number_nodes);
...
free(nodes);

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

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

0 голосов
/ 08 мая 2018

Если ваша реализация C поддерживает VLA в стиле C.1999, просто определите ваш массив.

Node Neighbors[numNeighbors];

(Обратите внимание, что VLA не имеет механизма сообщения об ошибках. Неудачное размещение приводит к неопределенному поведению, которое, вероятно, выражается в виде сбоя.)

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

Node *Neighbors = calloc(numNeighbors, sizeof(*Neighbors));

Обратите внимание, не приводите результат malloc / calloc / realloc при программировании на C. Это не требуется, а в худшем случае может маскировать фатальную ошибку.

0 голосов
/ 08 мая 2018

malloc и calloc предназначены для динамического размещения, и им нужны переменные-указатели. Я не вижу смысла использовать динамическое размещение. Просто определите обычный массив, пока у вас нет причин не делать этого.

#define MAXQ 100
#define NUM_NEIGHBORS 50

typedef struct {
  int state[MAXQ];
  int height;
} Node;

int main(void)
{
  Node Neighbors[NUM_NEIGHBORS];

  Neighbors[0].state[0] = 0;
  Neighbors[0].height = 1;
}

Здесь NUM_NEIGHBORS должен быть константой. (Следовательно, статический). Если вы хотите, чтобы он был переменным или динамическим, то вам нужны динамические выделения и указатели неизбежно:

#define MAXQ 100

typedef struct {
  int state[MAXQ];
  int height;
} Node;

int main(void)
{
  int numNeighbors = 50;
  Node *Neighbors;

  Neighbors = (Node*)calloc(numNeighbors, sizeof(Node));
  Neighbors[0].state[0] = 0;
  Neighbors[0].height = 1;
}
0 голосов
/ 08 мая 2018

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

Node Neighbors[10];

Затем вы можете ссылаться на них, как на любой другой массив, например:

Neighbors[3].height = 10;
...