Как создать массив структур на C?

101

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

У меня не так много опыта работы со структурами, поэтому я решил попробовать использовать их вместо целой кучи массивов. Однако я продолжаю сталкиваться с множеством различных ошибок. Я пытался реализовать методы, которые я видел в различных потоках и в StackOverflow (например, Массив структур в C и C - инициализировать массив структур ), однако не все из них были применимы.

Дополнительная информация для тех, кто дочитал до этого места: мне не нужно, чтобы все это было динамическим, я знаю / определяю размер всего заранее. Мне также нужно, чтобы это был глобальный массив, поскольку я обращаюсь к нему с помощью нескольких разных методов, которые имеют определенные аргументы (например, методы GLUT).

Вот как я определяю структуру в моем заголовке:

struct body
{
    double p[3];//position
    double v[3];//velocity
    double a[3];//acceleration
    double radius;
    double mass;
};

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

struct body bodies[n];

Просто чтобы вы знали, nэто то, что я правильно определил (т.е. #define n 1).

Я использую этот массив в нескольких различных методах, но самый простой и наименее занимающий много места из них - это упрощенная форма моего файла main. Здесь я инициализирую все переменные в каждой из структур, просто чтобы установить переменные наверняка, прежде чем я изменю их каким-либо образом:

  int a, b;
 for(a = 0; a < n; a++)
 {
        for(b = 0; b < 3; b++)
        {
            bodies[a].p[b] = 0;
            bodies[a].v[b] = 0;
            bodies[a].a[b] = 0;
        }
        bodies[a].mass = 0;
        bodies[a].radius = 1.0;
 }

Текущая ошибка, с которой я столкнулся, - это nbody.c:32:13: error: array type has incomplete element typeстрока 32, в которой я создаю массив структур.

И последнее уточнение: под заголовком я подразумеваю пространство выше, int main(void)но в том же *.cфайле.

Amndeep7
источник
Ну, у меня работает нормально. Разве вы не декларируете struct body bodies[n];перед struct body {}декларацией?
Джек
Обратите внимание, что использование массивов переменной длины может часто вызывать загадочные ошибки или сбои, когда размер массива превышает размер стека программы в вашей системе (что полностью вне вашего контроля как программиста). Для такого рода вещей лучше использовать malloc ().
Адриан

Ответы:

107
#include<stdio.h>
#define n 3
struct body
{
    double p[3];//position
    double v[3];//velocity
    double a[3];//acceleration
    double radius;
    double mass;
};

struct body bodies[n];

int main()
{
    int a, b;
     for(a = 0; a < n; a++)
     {
            for(b = 0; b < 3; b++)
            {
                bodies[a].p[b] = 0;
                bodies[a].v[b] = 0;
                bodies[a].a[b] = 0;
            }
            bodies[a].mass = 0;
            bodies[a].radius = 1.0;
     }

    return 0;
}

это отлично работает. кстати, ваш вопрос был не очень ясен, поэтому сопоставьте макет исходного кода с приведенным выше.

нимы
источник
Кроме того, у меня есть вопрос о размещении между объявлением типа структуры и фактическим созданием его экземпляра - у меня есть другая структура, содержимое которой я определил ниже, где я сначала делаю ее экземпляр (только один на этот раз не массив), так почему же это не привело к огромной серии ошибок? Это сработало просто отлично, и я подумал, что моя попытка создать массив тоже должна была сработать, но на этот раз она не сработала. Также спасибо за ваш ответ, это сработало.
Amndeep7
1
Привет .... 59 лайков? Я не видел массивов структур, я вижу только массивы переменных от ударил ...
12

Думаю, можно было бы и так написать. Я тоже студент, поэтому понимаю вашу борьбу. Немного запоздалый ответ, но нормально.

#include<stdio.h>
#define n 3

struct {
    double p[3];//position
    double v[3];//velocity
    double a[3];//acceleration
    double radius;
    double mass;
}bodies[n];
Christakitos
источник
11

Итак, чтобы собрать все вместе, используя malloc():

int main(int argc, char** argv) {
    typedef struct{
        char* firstName;
        char* lastName;
        int day;
        int month;
        int year;

    }STUDENT;

    int numStudents=3;
    int x;
    STUDENT* students = malloc(numStudents * sizeof *students);
    for (x = 0; x < numStudents; x++){
        students[x].firstName=(char*)malloc(sizeof(char*));
        scanf("%s",students[x].firstName);
        students[x].lastName=(char*)malloc(sizeof(char*));
        scanf("%s",students[x].lastName);
        scanf("%d",&students[x].day);
        scanf("%d",&students[x].month);
        scanf("%d",&students[x].year);
    }

    for (x = 0; x < numStudents; x++)
        printf("first name: %s, surname: %s, day: %d, month: %d, year: %d\n",students[x].firstName,students[x].lastName,students[x].day,students[x].month,students[x].year);

    return (EXIT_SUCCESS);
}
Дунчан
источник
8
Должна ли ваша строка malloc иметь numStudents * sizeof (STUDENT)?
Todd
@Todd Лучше не делать этого. sizeof *studentsэто то же самое, и не будет ничего плохого, если СТУДЕНТ когда-нибудь изменится.
trentcl
@trentcl Он выделил память для {numStudents} указателей. Не структуры, а указатели. Размер указателя обычно составляет 4 байта, в то время как размер структуры составляет 20 байтов. 20 байт - это число, кратное 4, поэтому заполнение не требуется, и структура сохраняется на каждом 20-м байте от начального адреса. Это работает только потому, что вы выделяете память только для одного конкретного случая. В противном случае другие маллоки могут перезаписать память ваших структур, потому что она не выделена, и вы переполнили память ученика.
Джон Смит
3
@JohnSmith Вы ошибаетесь; прочитай еще раз. sizeof *studentsэто размер того, на что указывает , т. е. sizeof(STUDENT)нет sizeof(STUDENT*). Вы делаете именно ту ошибку, от которой ptr = malloc(num * sizeof *ptr)идиома должна защищать. Проверьте это здесь (обратите внимание, что сервер, как и большинство современных ПК, имеет 8-байтовые указатели, поэтому размеры составляют 8 и 32 вместо 4 и 20).
trentcl
@trentcl Спасибо за объяснение. Меня смутил синтаксис разыменования указателя в его собственной инициализации. Я бы сказал, что это немного запутанное, но определенно более компактное решение.
Джон Смит
8

шаг

struct body bodies[n];

после

struct body
{
    double p[3];//position
    double v[3];//velocity
    double a[3];//acceleration
    double radius;
    double mass;
};

Остальное все выглядит нормально.

vrk001
источник
6

Другой способ инициализации массива структур - явная инициализация членов массива. Этот подход полезен и прост, если членов структур и массивов не так много.

Используйте typedefспецификатор, чтобы избежать повторного использования structоператора каждый раз, когда вы объявляете структурную переменную:

typedef struct
{
    double p[3];//position
    double v[3];//velocity
    double a[3];//acceleration
    double radius;
    double mass;
}Body;

Затем объявите свой массив структур. Инициализация каждого элемента сопровождается объявлением:

Body bodies[n] = {{{0,0,0}, {0,0,0}, {0,0,0}, 0, 1.0}, 
                  {{0,0,0}, {0,0,0}, {0,0,0}, 0, 1.0}, 
                  {{0,0,0}, {0,0,0}, {0,0,0}, 0, 1.0}};

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

Абдель Алим
источник
1
Люблю это! Хороший и простой ответ 👍
Итан
1

Это означает , что ошибка , что компилятор не может найти определение типа вашей структуры перед объявлением массива структур, так как вы говорите , у вас есть определение структуры в файл заголовок и ошибка в nbody.cто вы должны проверить, правильно ли вы включаете файл заголовка. #includeПеред объявлением какой-либо переменной этого типа проверьте свой и убедитесь, что определение структуры выполнено.

Дэвид
источник
Я сомневаюсь, что OP означает заголовок как файл заголовка, как он писал: «строка ниже находится над материалом выше» перед объявлением массива структуры, которое находится в его файле nbody.c. Подождем, пока он проснется и развеет сомнения.
нимс 06
@nims правильный, под заголовком я имел в виду область над mainоператором.
Amndeep7
1

Решение с использованием указателей:

#include<stdio.h>
#include<stdlib.h>
#define n 3
struct body
{
    double p[3];//position
    double v[3];//velocity
    double a[3];//acceleration
    double radius;
    double *mass;
};


int main()
{
    struct body *bodies = (struct body*)malloc(n*sizeof(struct body));
    int a, b;
     for(a = 0; a < n; a++)
     {
            for(b = 0; b < 3; b++)
            {
                bodies[a].p[b] = 0;
                bodies[a].v[b] = 0;
                bodies[a].a[b] = 0;
            }
            bodies[a].mass = 0;
            bodies[a].radius = 1.0;
     }

    return 0;
}
Помогая Бобу
источник