Photon и массивы указателей.

Есть в фотоне такой виджет — PtList.
Собственно, предоставляет те же возможности, что и компонент с подобным названием в любой другой среде: формирование списков, получение индекса выбранных элементов и т.п.
Ну и, естественно, фотоновская фишка — создание на его основе других виджетов, наследующих те же свойства и возможности.

Как добавить в уже созданный экземпляр PtList список элементов? QSSL заботится о Вас! Для этого есть специальная функция — PtListAddItems():

int PtListAddItems( PtWidget_t *widget,
                    const char **items,
                    int item_count,
                    unsigned int position );

В качестве списка строк эта функция принимает переменную типа const char **, и вот тут могут возникнуть проблемы.

Предположим, что наше приложение, создающее ГУИ, получает данные для инициализации откуда-либо извне.

В том числе, извне приходит и массив строк, который должен быть помещен в PtList.

Т.е. имеем нечто вроде такого кода:

char itemsList[20][20];

void
init_read(void* arg){
	int fd;

    fd = open(GUI_PORT, O_RDONLY | O_NOCTTY );

    if (fd == -1){
      	perror("nopen() failed! ");
		return( 0 );
    } else {
	read(fd,itemsList,400);
	}
close(fd);
}

После выполнения которого itemsList указывает на 20 хороших, годных строк, завершенных терминаторами, которые, как некоторые считают, можно бы сразу пихать в PtListAddItems:

PtListAddItems( widget, (const char **)itemsList,20,1);

Не беда даже несходство типов — фокусы с приведением спасают риальне джыгитов от надоедливых варнингов в любой ситуации. После запуска можно посмотреть, как приложение погибает с SIGSEGV.

Причиной столь вальяжного его поведения является непонимание разницы между между двумерным массивом и массивом указателей.

Для двух следующих определений:

int a[20][20];
int *b[20];

записи a[3][4] и b[3][4] будут синтаксически правильным обращением к некоторому значению типа int.

Однако только a является двумерным массивом: для четырехсот элементов типа int будет выделена память, а вычисление смещения элемента a[строка][столбец] от начала массива будет вестись по формуле 20 * строка + столбец, учитывающей его прямоугольную природу.

Для b же определено только 20 указателей, причем без инициализации. Инициализация должна задаваться явно — либо статически, либо в программе. Важное преимущество массива указателей в том, что строки такого массива могут иметь разные длины.

Так вот, PtListAddItems ждет массив указателей, который мы ей и передадим с небольшим вывертом:

void set_list(){
    char itemsList[20][20];
    char *items[20];
    int i;

    for( i=0; i<20; i++ ){
      items[i] = itemsList[i];
   }

   PtListAddItems( widget, (const char **),20,1);
}

Фотон в этом случае получает 20 идущих подряд указателей на строки, а мы — работающий виджет.

Похожий бред:

Photon и массивы указателей.: 3 комментария

  1. Обратите внимание, что в последнем примере char itemsList[20][20]; резервирует память в стеке функции! А Photon, которому мы указатели на эти строки передаем, может «затребовать» их уже после того, как функция отработала и вернула стек. Соответственно, когда прийдет время отрисовки, Photon возьмет мусор по старым указателям, и кирдык…

    Я вот в таких случаях память под строки выделяю старым добрым calloc() …

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Protected by WP Anti Spam