Як створити масив структур у C?


100

Я намагаюся створити безліч структур, де кожна структура представляє небесне тіло.

У мене не так багато досвіду зі структурами, саме тому я вирішив спробувати використовувати їх замість цілої маси масивів. Однак я продовжую натрапляти на численні різні помилки. Я намагався реалізувати прийоми, які я бачив у різних потоках та на 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).

Я використовую цей масив кількома різними методами, але найпростіший і найменш витратний простір - це спрощена форма мого основного. Тут я ініціалізую всі змінні в кожній зі структур, щоб просто встановити змінні для певних, перш ніж я їх якось модифікую:

  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файлі.


Ну, це добре працює для мене. Ви не заявляєте 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;
}

це працює добре. Ваше питання, до речі, було не надто зрозумілим, тож узгоджуйте макет вихідного коду з вищезазначеним.


Крім того, у мене є питання про розміщення між оголошенням типу struct, а потім фактично зробити його екземпляр - у мене інша структура, та, яку я визначив вміст нижче, де я вперше роблю його екземпляр (лише один цього разу, а не масив), так чому це не зробило масивної серії помилок? Це спрацювало чудово, що змусило мене думати, що моя спроба створити масив повинна була також спрацювати, але цього разу вона не спрацювала. Крім того, дякую за вашу відповідь, це спрацювало.
Amndeep7,

1
Привіт, .... 59 вподобань? Я не бачив масивів struct, я бачу лише масиви змінних від

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];

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 Краще не робити. 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;
};

Відпочинок все виглядає нормально.


6

Інший спосіб ініціалізації масиву структур - це явна ініціалізація членів масиву. Цей підхід є корисним і простим, якщо членів структури та масиву не надто багато.

Використовуйте typedefспецифікатор, щоб уникнути повторного використання structоператора кожного разу, коли ви оголошуєте змінну 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}};

Повторюємося, це досить просте і зрозуміле рішення, якщо у вас немає занадто багато елементів масиву та великих членів структури, і якщо вас, як ви вже заявили, не цікавить більш динамічний підхід. Цей підхід також може бути корисним, якщо члени структури ініціалізовані з іменованими змінними enum (а не лише числами, як у прикладі вище), завдяки чому він дає читачеві коду кращий огляд призначення та функцій структури та її членів у певних додатків.


1
Люблю це! Приємна і проста відповідь 👍
Ітан,

1

Ця помилка означає, що компілятор не може знайти визначення типу вашої структури до оголошення масиву структур, оскільки ви говорите, що ви маєте визначення структури у файлі заголовка, а помилка в nbody.cтому слід перевірити, чи правильно ви включаєте файл заголовка. Перевірте свої #includeі переконайтеся, що визначення структури виконано перед оголошенням будь-якої змінної цього типу.


Я сумніваюся, що OP означає заголовок як файл заголовка, як він писав, "рядок внизу знаходиться над матеріалом вгорі" перед оголошенням масиву struct, яке знаходиться у його файлі nbody.c. Давайте почекаємо, поки він прокинеться і очистить сумнів.
німи

@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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.