Вопрос новичка о массивах в структурах в C ++ - PullRequest
1 голос
/ 18 июня 2011

Я хотел бы создать структуру и использовать ее внутри другой структуры в качестве массива. Моя проблема в том, что я не знаю, какой большой массив я бы хотел выделить, я буду знать только, когда попаду в функцию. Я имею в виду, что я хотел бы использовать [] вместо заранее определенной константы, например, 10000.

Я думаю, что если вы посмотрите на мой код, это само за себя. Можете ли вы помочь мне, как заставить этот код работать? Кроме того, мне бы очень помогло, если бы вы могли сказать мне, как называется тема, о которой я спрашиваю (это динамические массивы?) И где я могу найти статьи / учебные пособия по этой теме.

Вот код моего неправильного представления о массивах в структурах.

#include <iostream>

using namespace std;

struct keyframe {
    bool a;
    int b;
    int c;
};


struct keyframe_file {
    const int num_views;
    const int num_keyframes;
    keyframe keyframes[];
};


int main() {

    keyframe_file my_file;

    my_file.num_views = 1;
    my_file.num_keyframes = 6;

    my_file.keyframes = new keyframe[my_file.num_keyframes];

    my_file.keyframes[0].a = true;
    my_file.keyframes[0].b = 5;
    my_file.keyframes[0].c = 9;

    return 0;

}

Ответы [ 7 ]

5 голосов
/ 18 июня 2011

Используйте std::vector.

struct keyframe_file {
    const int num_views;
    const int num_keyframes;
    std::vector<keyframe> keyframes;
};

int main() {
    keyframe_file frame;
    frame.keyframes.resize(...);
}
0 голосов
/ 18 июня 2011

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

#include <iostream>

using namespace std;

struct keyframe {
    bool a;
    int b;
    int c;
};


struct keyframe_file {
    const int num_views;
    const int num_keyframes;
    keyframe* keyframes;
};


int main()
{
    keyframe_file my_file = {1, 6};  // initialization needed bcause of 'const int'

    my_file.keyframes = new keyframe[my_file.num_keyframes];

    for (int i = 0; i < my_file.num_keyframes; i++)
    {
        my_file.keyframes[i].a = true;
        my_file.keyframes[i].b = 5 + i;
        my_file.keyframes[i].c = 9 - i;
    }
    return 0;
}

где-то в вашем коде, когда вы закончите использовать массив, вы должны вызвать delete [] my_file.keyframes;, как уже упоминалось.

0 голосов
/ 18 июня 2011

Существует базовое правило при использовании динамических массивов в c ++, особенно при использовании его внутри структур или классов, и это для удаления того, что вам больше не нужно.

Если вы хотите сделать вашу структуру динамической, это легкопросто замените [] на *, и массив станет динамическим, но он еще не закончен, много работы.

Вы должны создать массив, уничтожить его и уничтожить егоЭто возможно и полезно с помощью деструкторов, например:

struct keyframe_file
{
    const int num_views;
    const int num_keyframes;
    keyframe* keyframes;

    ~keyframe_file() // this is the destructor
    {
        delete[] keyframes;
    }
};

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

Использование классов с динамическими массивами очень просто и интересно и делает ваш код очень хорошим, вам не нужно слишком много знать, чтобы это сделать, просто узнайте, чтоявляется конструктором , инициализатором , деструктором , private и public и далее со следующимикод:

#include <iostream>

using namespace std;

struct keyframe
{
    bool a;
    int b,c;
};

class keyframe_file
{
public:
    keyframe_file(int NV, int NKF):num_keyframes(NKF),num_views(NV)
    {
        keyframes = new keyframe[num_keyframes];
    }
    ~keyframe_file()
    {
        delete[] keyframes;
    }
private:
    const int num_views;
    const int num_keyframes;
    keyframe* keyframes;
};

int main()
{
    keyframe_file my_file(1,6);
    return 0;
}

Этот код работает очень хорошо, он позволяет вам присвоить значение константам num_views и num_keyframes один раз при создании объекта (переменной) my_file.

Помните, что вы программист на C ++, гордитесь этим и используете классы вместо структур и динамических массивов вместо статических.

Надеюсь, это полезно.

0 голосов
/ 18 июня 2011

Если это соответствует вашим целям, контейнер STL (std::vector) - один из лучших вариантов: чем меньше управление памятью, тем лучше.

В любом случае, посмотрите на определение структуры, размещенное Навазом выше - именно так и должно быть. Динамические массивы в C ++ - это просто указатели. Вы, однако, правильно распределили память в своем коде, но не освободили ее (поэтому она течет). Поскольку вы выделили new [], вам потребуется

delete [] my_file.keyframes;

для правильного освобождения памяти.

Изменение размера - это еще одна проблема: при умной реализации изменение размера массива может быть амортизированной операцией O (1), что приятно. Когда вы изменяете размер, вам всегда потребуется O (n), так как вам нужно скопировать все элементы в новый массив другого размера, но если вы сделаете это вдвое меньше, он станет O (1). То есть удваивайте массив каждый раз, когда вам нужно изменить размер. Вот очень быстрый пример

void resize()
{
  if(numOfElementsInArray == sizeOfArray)
  {
    ArrayType * arr = new ArrayType[sizeOfArray*2]; // Allocate a double size array
    for(int i=0;i<sizeOfArray;++i)
      currentArray[i] = arr[i];
    delete [] currentArray; // Free memory in old array
    currentArray = arr; // Set the array to our new one
    sizeOfArray *= 2; // Double the size
  }
}

ПРИМЕЧАНИЕ: В приведенном выше примере не учитывается сложность пространства; Тем не менее, если у вас есть 5000 элементов, и удалите все, кроме 5, этот метод не сжимает его (что, вероятно, вы захотите сделать для всех практических целей)

0 голосов
/ 18 июня 2011

Это неполный тип.В C ++ для массива должен быть указан размер, а размер должен быть известен во время самой компиляции.

Вы используете new, с которым вам следует использовать указатель .

struct keyframe_file {
    const int num_views;
    const int num_keyframes;
    keyframe *keyframes;
};

Но std::vector<keyframe> все еще лучший выбор, как уже предлагал @DeadMG.

Кстати, первые два члена в структуре const, это означает, что они не могут быть назначенным значением, как вы делаете в своемкод.Они должны быть инициализированы со значениями, которые вы хотите их сохранить.Это означает, что теперь с vector вы должны включить конструктор для инициализации структуры, так как структура не более POD.

struct keyframe_file {
    const int num_views; //const member
    const int num_keyframes; //const member
    std::vector<keyframe> keyframes;

    keyframe_file(int nviews, int nkeyframes) 
    : num_views(nviews), num_keyframes(nkeyframes), keyframes(nkeyframes){}
};


keyframe_file my_file(1,6); //done!
0 голосов
/ 18 июня 2011

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

  1. keyframes должно быть keyframe*, а не keyframe[]
  2. Вы забыли delete память, которую вы выделили
0 голосов
/ 18 июня 2011

Используйте указатели и применяйте к своей структуре!

int *p;
p = new int;

#include <iostream>
using namespace std;

struct keyframe {
    bool a;
    int b;
    int c;
};


struct keyframe_file {
    const int num_views;
    const int num_keyframes;
    keyframe *keyframes;
};


int main() {
    keyframe_file my_file;
    my_file.num_views = 1;
    my_file.num_keyframes = 6;

    for (int i = 0; i < my_file.num_keyframes; i++){
         my_file.keyframes = new keyframe; //<---
    }

    my_file.keyframes[0].a = true;
    my_file.keyframes[0].b = 5;
    my_file.keyframes[0].c = 9;

    return 0;

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