C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Как динамически создать структуру???, С заранее неизвестным кол-вом элементов
Guest
Отправлено: 30.03.2004, 17:37


Не зарегистрирован







Привет. Есть ListBox с заранее неизвестным количеством элементов в нем. После заполнения юзером данного ListBox-а, нужно динамически создать структуру и заполнить её данными из ListBox-а.

Т.е. я пытаюсь сделать что-то типа:
CODE

struct Parameters {
  AnsiString Pattern[];
  int a;
  bool flag;
 };
 Parameters &Params = *new Parameters;
 for(int i = 0; i < ListBox1->Items->Count; i++)
  {
   Params.Pattern[i] = ListBox1->Items->Strings[i];
  }


При этом вылетает Access Violation, оно то и понятно, т.к. неизвестен размер AnsiString Pattern[]; и к тому же он не проинициализирован...
Но в том то и все дело что я ж заранее не знаю сколько элементов будет в ListBox1 ??? И как же мне создать тогда структуру в подобной ситуации???

А если я пытаюсь объявить так:
CODE

struct Parameters {
  AnsiString Pattern[ListBox1->Items->Count];
  int a;
  bool flag;
 };


То тоже ругается, мол должно быть константное выражение...

Как быть?
Asher
Отправлено: 30.03.2004, 17:46


Мастер участка

Группа: Модератор
Сообщений: 550



использовать STL
например std::vector

Или вместо массива AnsiString используйте тот-же StringList biggrin.gif

или заведите указатель на массив AnsiString *Pattern
а в нужном месте Pattern = new AnsiString [Size];
главное потом не забыть delete [ ] Pattern;

Способов масса. biggrin.gif biggrin.gif biggrin.gif
Guest
Отправлено: 30.03.2004, 18:38


Не зарегистрирован







А можете привести примерчик, как это сделать через TstringList к примеру????
И что такое STL?
Guest
Отправлено: 30.03.2004, 19:02


Не зарегистрирован







И еще такой вопрос: к примеру у меня получилось, делал так
CODE

struct Parameters {
 AnsiString *Pattern;
 int a;
 bool flag;
};
Parameters &Params = *new Parameters;
Params.Pattern = new AnsiString[ListBox1->Items->Count];
for(int i = 0; i < ListBox1->Items->Count; i++)
 {
  Params.Pattern[i] = ListBox1->Items->Strings[i];
 }
delete &Params;


А если нужно сделать то же самое, только для двухмерного массива AnsiString, т.е. как объявить двухмерный массив AnsiString в данной структуре и выделить под него память??? . Как это все тогда будет выглядеть??? Привидите пожалуйста пример...
exp
Отправлено: 30.03.2004, 23:50


Мастер участка

Группа: Участник
Сообщений: 304



Допустим ьебе надо выделить массивчик двумерненький размером
ListBox1->Items->Count*N
Тады Вместо *Pattern — указателя на массив пишешь **Pattern — указатель на МАССИВ УКАЗАТЕЛЙ на AnsiString
Затем пробегаешься по массивчику и так же как и раньше выделяешь память под каждый из них.
CODE

struct Parameters {
AnsiString **Pattern;
int a;
bool flag;
};
Parameters *Params = new Parameters;
Params->Pattern = new AnsiString*[ListBox1->Items->Count];

for(int i=0; i<ListBox1->Items->Count;i++)
Params.Pattern[i] = new AnsiString[N]; //можем обращатся по индексу, т. к. массив уже существует в памяти.
/*
for(int i = 0; i < ListBox1->Items->Count; i++)
{
Params->Pattern[i] = ListBox1->Items->Strings[i];
}
*/
// Удаление:
for(int i=0; i<ListBox1->Items->Count;i++)
delete[] Params->Pattern[i];
delete[] Params;
// Удалили


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

include "vector.h"
//........
vector<AnsiString> MojPervijVector(0) // 0 означает, что первоначально в векторе 0 элементов.

Эта тема про вектор уже была. поищи по форуму. Просто впадлу один и тот же код писать.
wink.gif wink.gif

Отредактировано exp — 04/04/2004, 00:00
Asher
Отправлено: 31.03.2004, 08:08


Мастер участка

Группа: Модератор
Сообщений: 550



Привет.
Я ж говорил, не забывай делать delete.

если ты сделал
Params.Pattern = new AnsiString[ListBox1->Items->Count];
то где
delete [] Params.Pattern; ???
Snake
Отправлено: 31.03.2004, 09:45


Ученик-кочегар

Группа: Участник
Сообщений: 22



QUOTE (Guest @ 30/03/2004, 18:39)
Привет. Есть ListBox с заранее неизвестным количеством элементов в нем. После заполнения юзером данного ListBox-а, нужно динамически создать структуру и заполнить её данными из ListBox-а.


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

CODE

struct Parameters {
  AnsiString Pattern[];
  int a;
  bool flag;
 };

 TList *Params = new TList();
  for(int i = 0; i < ListBox1->Items->Count; i++)
  {
         Params->Add( new Parameters(ListBox1->Items->Strings[i]) );
  }  


A извлекать данные из Params следующим образом:

Parameters *p = (Parameters*) Params->Items[i];

Если функциональности TList недостаточно, можно создать свой класс списка, породив его от TList.

xTrim
Отправлено: 31.03.2004, 11:05


Машинист паровоза

Группа: Участник
Сообщений: 208



CODE

#include <vector>
using std::vector;

struct Parameters
{
 vector<AnsiString> Pattern;
 int a;
 bool flag;
};

Parameters Params;

for(int i = 0; i < ListBox1->Items->Count; i++)
 {
  Params.Pattern.push_back(ListBox1->Items->Strings[i]);
 }
olegenty
Отправлено: 31.03.2004, 11:36


Ветеран

Группа: Модератор
Сообщений: 2412



если навороченая функциональность не нужна, а нужен чисто массив, рекомендую (цитата из справки Builder):

QUOTE

Multidimensional dynamic arrays

Dynamic arrays can be multidimensional. Multidimensional dynamic arrays don't have to be rectangular. The Length property can be used to set each dimension. The following example illustrates.

typedef DynamicArray< DynamicArray < AnsiString>> T2DStringArray;

void foo(T2DStringArray &s_array)
{
 SetLength(s_array, 10);
 for (int i=0; i  { // Set lengths of second dimensions.(NOTE: non-rectangular)
   SetLength(s_array[i], i+1);
   for (int j=0; j    /* */ s_array[i][j] = itoa(i*10+j);
 }
}
Guest
Отправлено: 31.03.2004, 14:06


Не зарегистрирован







Ребята, огромное спасибо что поделились соображениями, но реально попробовав те варианты которые вы предложили, 80% из них не рабочими оказались. Напимер код, который выложил exp не срабатывает и компилер матерится, тот же случай и с кодом, который предложил Snake, особенно мне, и компилятору тоже, непонятно выражение Params->Add( new Parameters(ListBox1->Items->Strings[i]) ); ??? Как оно относится к моей структуре?!
Плиз. Попробую поконкретнее объяснить свою задачу, может все-таки нарисуете код, который бы отработал и если можно с пояснениями...

Значит есть две формы: главная (основная форма проги) и дополнительная (форма для разных настроек). Дык вот в той форме которая отвечает за настройки, мне нужно организовать сохранение всех опций и потом записать их в реестр. Чтобы хранить опции, я и решил воспользоваться структурой. Но поскольку в опциях, среди CheckBox-ов и RadioButton-ов используется ListBox, в которм юзер может добавлять сколько угодно строк (кол-во заранее не известно) , то
структуру наверное нужно делать динамической, ну по крайней мере тот элемент структуры, в котором для ListBox-а нужно место отводить.
И еще нужно сделать так, чтобы доступ к этой структуре можно было получить как из основной формы, так и из дополнительной, а это наверное означает что в структуре нужно делать не указатель на AnsiString в который запихивать данные из ListBox-а, а именно массив AnsiString?? Ведь ListBox существует только в дополнительной форме и после выхода из нее (форма ведь уничтожается) указатель будет указывать в никуда и я в основной фроме не смогу получить доступ непосредственно к данным в структуре?? ..... Помогите разобраться...

Может кто-нибудь конкретно, на примере (рабочем) показать как это сделать??? а?? плиз....

Допустим есть:
CODE

TMain *Main; //главная форма
TOptions *Options; //дополнительная форма
//и структура
struct Parameters {
 AnsiString Pattern[]; //сюда должны запихиваться данные из ListBox-а, но не знаю что лучше использовать: указатель или массив?!
 int a;
 bool flag;
};


И как это все будет в рабочем виде?
Георгий
Отправлено: 31.03.2004, 23:13


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



Лекарство в данном случае одно — купить книжку по BCB и по STL. Также есть подозрение что книга просто о c++ не помешает.

PS. вариант предложенный xTrim`ом полностью рабочий
PPS. указатель на форму после её закрытия не теряет своей актуальности
olegenty
Отправлено: 01.04.2004, 08:33


Ветеран

Группа: Модератор
Сообщений: 2412



Тут запахло коллекцией, вынесенной в отдельный компонент. Для этого надо создать наследника от TCollectionItem, и наследника от TCollection. Получится универсальное решение, если в компонент включить коллекции элементов разных типов: и строк, и целых чисел и т.д...
Snake
Отправлено: 01.04.2004, 10:37


Ученик-кочегар

Группа: Участник
Сообщений: 22



QUOTE (Guest @ 31/03/2004, 15:08)
и с кодом, который предложил Snake, особенно мне, и компилятору тоже, непонятно выражение Params->Add( new Parameters(ListBox1->Items->Strings[i]) ); ??? Как оно относится к моей структуре?!

Cори, лажанулся, невнимательно прочитал, что нужно.
Вот, сделал рабочий пример (в принципе, то же самое, что и в варианте xTrim)

CODE

      struct Parameters
       {
           public:
           Parameters() { Pattern = new TStringList(); }
           TStrings* Pattern;
           int a;
           bool flag;
       };

       Parameters p;
       //Запись
       for (int i=0; i < 10; i++ )
           p.Pattern->Add( AnsiString("значение")+IntToStr(i) );

       //Чтение
       for ( int i=0; i < 10; i++ )
           ShowMessage( p.Pattern->Strings[i] );


В общем случае, вместо TStrings можно использовать TList.

xTrim
Отправлено: 01.04.2004, 10:56


Машинист паровоза

Группа: Участник
Сообщений: 208



CODE

     struct Parameters
      {
          public:
          Parameters() { Pattern = new TStringList(); }
// не забыть
          Parameters() { delete Pattern; }
//
          TStrings* Pattern;
          int a;
          bool flag;
      };
Guest
Отправлено: 01.04.2004, 13:22


Не зарегистрирован







Всем еще раз спасибо за помощь. Со структурой разобрался smile.gif
Возник другой вопрос. Тут Георгий говорил:
QUOTE
указатель на форму после её закрытия не теряет своей актуальности

И действительно так. Значит для эксперемента в хэдере главной формы написал:
CODE

struct Parameters {
        AnsiString *Pattern;
       }*Params;

В cpp главной формы:
CODE

Params = new Parameters;
TOptions *Options = new TOptions(this);
Options->ShowModal(); //Вызвал дополнительную форму

В cpp дополнительной формы:
CODE

Main->Params->Pattern = new AnsiString[ListBox1->Items->Count];
for(int i = 0; i < ListBox1->Items->Count; i++)
 Main->Params->Pattern[i] = ListBox1->Items->Strings[i];

Теперь, по идее Params->Pattern указывает на ListBox1->Strings[]
Но даже после того как в главной форме я зачудил
CODE

delete Options;
// то потом смог добратся до значений ListBox1
for(int i = 0; i < n; i++)
 ShowMessage(Params->Pattern[i]);

Но каким образом? если я убил дополнительную форму со всеми её компонентами, указательParams->Pattern[] указывает на значения? откуда они берутся, если убита форма и ListBox1 в частности? куда же тогда указывает Params->Pattern[] ??
Объясните плиз этот момент......
Георгий
Отправлено: 01.04.2004, 21:57


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



QUOTE (Guest @ 01/04/2004, 14:24)
Но каким образом? если я убил дополнительную форму со всеми её компонентами, указательParams->Pattern[] указывает на значения? откуда они берутся, если убита форма и ListBox1 в частности? куда же тогда указывает Params->Pattern[] ??
Объясните плиз этот момент......

Ничего ты не убил — при закрытии форма только прячется. Отсюда и факт живости всех указателей.
Guest
Отправлено: 02.04.2004, 13:26


Не зарегистрирован







Хм...... всегда думал что delete высвобождает выделенную память?! Дык что это получается, что память все таки используется? Какже тогда окончательно её высвободить, если я форму создавал с помощью new ??
Asher
Отправлено: 02.04.2004, 13:50


Мастер участка

Группа: Модератор
Сообщений: 550



Привет.
Не... если сделал delete Options; то форму ты конечно прибил.
Но если никто память не попортил, то так все на месте и лежит.
Ты лезешь не в свою память (хакеры или вирусы как думаешь работают ? ) и получаешь свои данные. И до поры до времени все нормально.
Если ты между delete Options; и своим циклом вставишь создание — подходящих по размеру объектов, чтобы память забили — получишь Аксесс Вуаля. biggrin.gif
Guest
Отправлено: 02.04.2004, 15:01


Не зарегистрирован







Всем огромное спасибо за лекцию. smile.gif)
exp
Отправлено: 03.04.2004, 22:59


Мастер участка

Группа: Участник
Сообщений: 304



Прошу прощения за серость. Код исправлен.
З.Ы. Еслы компилер выдает ошибки типа
[C++ Error] Unit1.cpp(45): E2206 Illegal character ' ' (0xa0)
То нада была подредактировать код и поудалять непечатные символы.

Вернуться в Вопросы программирования в C++Builder