Урок: разбираем списки, часть 1 : Эльфостроение : Форум


 arban:
09.11.09, 19:22
 И так, цель нашего урока - понять зачем нужны списки объектов (LIST'ы, листы). Допустим, нам надо сделать эльф, который будет читать из файла какие-то данные и выводить их удобным образом, например в виде пунктов, или выводить список файлов в папке - примеров можно придумать кучу. Таким образом - листы помагают удобно и быстро распределять объекты в памяти. Это удобство достигается специальными функциями для работы со списками:

Код: 
LIST *List_New(void);
void List_Free(LIST *lst);
void ListElement_AddtoTop(LIST *lst,void *newElement);
void * ListElement_Remove(LIST *lst,int index);
int ListElement_Prt2NumElement(LIST *lst,void *ptr);
int ListElement_Find(LIST *lst,void *element, int (*cmp_proc)(void *,void *));
void * ListElement_GetByIndex(LIST * , int index);
void ListElement_Add(LIST *lst,void *newElement);
void List_FreeElements(LIST *,int (*cmp_proc)(void * elem_from_list),void (*freefunc)(void * elem_from_list));
void ListElement_Insert(LIST *lst, int i, void *new_item);


Сейчас все функции мы разбирать не будем, а рассмотрим основные моменты.

Для начала необходимо создать список. Он будет находится в переменной list. Перед этим расскажу немного о структуре LIST:

Код:
typedef struct
{
  u16 unk;//неизвестно
  u16 FirstFree;//кол-во пунктов
  void **listdata;//массив с данными
}LIST;


Теперь приступим!

1. Объявляем list как указатель:

Код:
LIST * list;


2. Создаем свою структуру, содержащую какое-то число и строку, и называем её ITEM:

Код:
typedef struct
{
   int number;// число
   wchar_t * string;//строка
}ITEM;


3. Пишем функцию для создания списка, она не будет возвращать никакого значения, поэтому её тип - void, также она не содержит параметров. Я делаю для этого отдельную функцию только для оптимизации при использовании её в нескольких местах, да и код выглядит красивее. Ещё советую давать понятные имена функциям, например: List_Create, List_Destroy, List_Save и т.д.

Код: 
void List_Create()
{
 list=List_New();//выделяем память под список
 for(int i=0;i<10;i++)//запускаем цикл для добавления 10-ти пунктов
  {
    ITEM *item=new ITEM; //создаем новую переменную типа ITEM
    memset(item,0,sizeof(ITEM));// выделяем для неё память
    item->number=i;//присваиваем переменной number в структуре ITEM текущего пункта значение i
    wchar_t buf[1];//создаем так называемый буффер, для хранения временной строчки
    //тип wchar_t - строка в кодировке Unicode
    snwprintf(buf, 2, L"%d", i);//функцией записываем в буффер число как строку
    item->string=new wchar_t[wstrlen(buf)+1];// выделяем память под строку
    //string в структуре ITEM в размере буффера buf
    //единицу прибавлять в таком случае обязательно! 
    //иначе символ L'\0' не запишется в строку
    wstrcpy(item->string, buf); //наконец, копируем в item->string строку buf
    ListElement_Add(list, item);//добавляем всё это дело в список
  }  
}


Вроде бы всё расписал тут, что не понятно - не стесняйтесь спрашивать. Эту функцию очень легко отредактировать под свои

нужды.

4. Теперь пришло время функции уничтожения списка, назовем её List_Destroy, также для удобства напишем простенький макрос:

Код:
#define DELETE(a) if (a) {delete(a);a=0;} //если объект a не равен 0, то очищаем память, занятую им

Код: 
void List_Destroy()
{
if (list)//если список list существует
  {
    while (list->FirstFree)//если есть ещё пункты в списке
    {
      ITEM* it=(ITEM*)ListElement_Remove(menu->list,0);//удаляем пункт с индексом(номером) 0 
      //из списка и присваиваем его указатель переменной it.
      //Можно удалять и последний пункт, но так удобней.
      DELETE(it->string);// очищаем память, выделенную под строку it->string
      DELETE(it);//очищаем память, выделенную под сам пункт it
    }
    List_Free(list);//удаляем список
  }
}



Если вы не поняли зачем List_Destroy - при создании списка вы выделяли память под список, пункты, строки в пунктах, если это

всё не "убивать" то происходит утечка памяти, тоесть нужно очистить память, занятую этими объектами.

5. Располагаем функции где нам необходимо, например:

- List_Create помещаем в main
- List_Destroy в onMyBookClose (в ту функцию, где обрабатывается ивент закрытия книги)

Лучше всего уничтожать лист, когда он уже не используется.

Вот, собственно, на сегодня и всё. Что не так, не понятно и т.д. - отписывайтесь :)

(c)arban

 den_po:
09.11.09, 19:33
 
arban пишет:
- List_Destroy обязательно (!!!) помещать при закрытии книги

смущает это заявление

куча списковых функций, тех, что есть в либе, и что нету, описана тут http://supertrubka.org/wiki/doku.php?id=index&idx=firmware

 mmcorp:
30.09.10, 21:31
 я бы рекомендовал в функции List_Destroy() удалять последний элемент из списка, так как при его "выемки" из списка сдвига элементов происходить не будет, работать очищение листа будет в разы быстрее, особенно для листов с количеством элементов >>5000

URL этой темы:
https://mobilefree.justdanpo.ru/newbb_plus/viewtopic.php?topic_id=4462

© 2005-2018 supertrubka.org