Easyelectronics.ru

Электроника для всех
Текущее время: 22 авг 2019, 21:06

Часовой пояс: UTC + 5 часов



JLCPCB – Прототипы печатных плат за $2/10pcs (Любой цвет!)
Крупнейший производитель печатных плат и прототипов. Более 600000 клиентов и свыше 10000 заказов в день!
Получите скидку на почтовую отправку при первом заказе в JLCPCB!

Начать новую тему Ответить на тему  [ Сообщений: 11 ] 
Автор Сообщение
 Заголовок сообщения: Си: Статический массив указателей на строки
СообщениеДобавлено: 25 июл 2017, 13:40 
Заглядывает иногда

Зарегистрирован: 12 апр 2011, 23:33
Сообщения: 40
Туплю второй день, вопрос следующий:

В программе использую строковые константы для реализации прокрутки списка данных, в моем случае - элементов меню. Заданы они так:
Код:
const static char* menuList[] = {"Spectrum Scan", "Scan Options", "Device Setup", "File Manager", "Clock View"};


Так это выглядит:
https://youtu.be/275PPhTWjbA

В функцию анимации передаю все через структуру, содержащую массив указателей на строки и номер главной (центральной) строки:
Код:
typedef struct
{
   char** text;
   int stringNum;
} myStruct_t;

void foo(myStruct_t* myStruct)
{
   ...
   sprintf((char*)tmpBuff, "%s", myStruct->text[myStruct->stringNum]);          //Вот так легко достучаться до любой строки
   sprintf((char*)tmpBuff, "%s", myStruct->text[myStruct->stringNum - 1]);     //До предыдущей
   sprintf((char*)tmpBuff, "%s", myStruct->text[myStruct->stringNum + 1]);    //Или до следующей
   ...
}

int main(void)
{
   myStruct_t myStruct = {.text = menuList};

   myStruct.stringNum = 0;    //Нулевая строка
   foo(&myStruct);

   myStruct.stringNum = 2;    //Вторая строка
   foo(&myStruct);
}


Но тут мне понадобилось, что бы строки были не константами, заданными при инициализации, а заполнялись нужными данными во время работы устройства. Ну и я по старинке статически объявил массив указателей на строки, заполнив их пробелами. И начал копировать туда данные:
Код:
static char* newList[] = {"     ", "     ", "     ", "     ", "     "};
strcpy(newList[0], "Hell");

Ага, щас. Хардфолт. Отладчик сказал, что все мои пробельный строки лежат по адресу 0x80_____ А значит, во FLASH. И что-то записывать туда весьма глупо. А я-то наивно полагал, что это можно задавать квалификатором const, но нет. Да и не очень-то красиво расширять массив при необходимости, добавляя пробелы или другие символы.

Кажется, можно как-то решить с использованием двумерного массива и двойного указателя на него - но ведь нельзя просто присвоить указателю на указатель имя статического двумерного массива.

Пока что работает так:
Код:
char*   A[3];
char   abc[3][5];

for(s8 i = 0; i < 3; i++)
{
   A[i] = abc[i];
}

Отдельно создается массив указателей и отдельно двумерный массив строк, потом циклически заносим в первый массив указателей адреса первых элементов.

Как это сделать грамотно и элегантно? Хочется, что бы сразу был массив указателей на строки в RAM, размер которого можно быстро менять.
Динамическое выделение RAM исключено. Строки все одинаковой длины, в отличие от списка меню, которое лежит во FLASH. Чувство, что решение очень простое и на поверхности - не отпускает.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Си: Статический массив указателей на строки
СообщениеДобавлено: 25 июл 2017, 14:02 
Старожил

Зарегистрирован: 23 янв 2016, 15:37
Сообщения: 988
Код:
static char* newList[] = {"     ", "     ", "     ", "     ", "     "};

Ты создал массив указателей, он то в ОЗУ, а сами строки уже нет. Нужно было сделать так:
Код:
static char newList[5][6] = {"     ", "     ", "     ", "     ", "     "};


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Си: Статический массив указателей на строки
СообщениеДобавлено: 25 июл 2017, 14:19 
Заглядывает иногда

Зарегистрирован: 12 апр 2011, 23:33
Сообщения: 40
Я так делаю сейчас, только вот двумерный массив
Код:
char newList[5][6];
нельзя привести к типу char** textList, который описан в структуре, которую я передаю в функцию анимации.

И ведь если я задаю двумерный массив, уже совсем не обязательно заполнять его пробелами - память уже выделена в RAM под 6 элементов типа char


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Си: Статический массив указателей на строки
СообщениеДобавлено: 25 июл 2017, 14:22 
Старожил
Аватара пользователя

Зарегистрирован: 29 янв 2010, 15:41
Сообщения: 1127
Откуда: Германия
Хе хе. умный компилятор оптимизирует ваш массив так, что массив будет проинициализирован одним единственным адресом, а по этому адресу будет там самая строка в 5 проблеов, причем в одном единственном экземпляре. Потому что строки как бы одинаковы, и потому компилятор во флешь один экземпляр воткнет.
Такое у меня было на AVR и на CC1010

_________________
Мои поделки
http://www.fun-electronic.net/


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Си: Статический массив указателей на строки
СообщениеДобавлено: 25 июл 2017, 14:28 
Заглядывает иногда

Зарегистрирован: 12 апр 2011, 23:33
Сообщения: 40
Ну нет, отладчик показывает все строки (все одинаковые строки) по разным адресам во FLASH. По крайней мере, с -O0. При включенной оптимизации возможно так и будет, но наверняка не знаю - отлаживать невозможно, указатель места выполнения прыгает постоянно непонятно куда.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Си: Статический массив указателей на строки
СообщениеДобавлено: 25 июл 2017, 14:43 
Старожил

Зарегистрирован: 23 янв 2016, 15:37
Сообщения: 988
Katbert писал(а):
Я так делаю сейчас, только вот двумерный массив
Код:
char newList[5][6];
нельзя привести к типу char** textList, который описан в структуре, которую я передаю в функцию анимации.
Передавая char* вместо char** можно получить доступ к нужной строке умножив индекс на длину строки, в данном случае на 6.

Цитата:
И ведь если я задаю двумерный массив, уже совсем не обязательно заполнять его пробелами - память уже выделена в RAM под 6 элементов типа char
Не нужно, но я же не знаю как у тебя там все работает, может первоначальное заполнение строк пробелами является критически важным :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Си: Статический массив указателей на строки
СообщениеДобавлено: 25 июл 2017, 14:54 
Старожил

Зарегистрирован: 22 июн 2010, 21:53
Сообщения: 1023
Откуда: Brussels
IMHO, не стоит инициализировать массив константами. А запись
Код:
= "    ";
это как раз инициализация константой. Т.к. вам требуется менять массив на ходу - обращайтесь с ним как должно - как с динамическим массивом. Выделение памяти (malloc или new) и инициализация через копирование (memncpy или что там есть еще).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Си: Статический массив указателей на строки
СообщениеДобавлено: 25 июл 2017, 15:15 
Старожил

Зарегистрирован: 10 фев 2016, 19:55
Сообщения: 269
Если правильно понял, то нужно менять указатели на строки в массиве 'menuList' и при этом длина массива постоянна, а меняются только строки, так?
Если так, то вот пример:
Код:
static char* menuList[] = {0, 0, 0, 0, 0};

typedef struct
{
   char** text;
   int stringNum;
} myStruct_t;

void foo(myStruct_t* myStruct)
{
   int arrSize = sizeof(menuList) / sizeof(char*);

   printf("%s\n", myStruct->text[myStruct->stringNum % arrSize]);          //Вот так легко достучаться до любой строки
   printf("%s\n", myStruct->text[(myStruct->stringNum + arrSize - 1) % arrSize]);     //До предыдущей
   printf("%s\n", myStruct->text[(myStruct->stringNum + 1) % arrSize]);    //Или до следующей
}

int main() {

   myStruct_t myStruct = {.text = menuList};

   char* m1 = "test1";
   char* m2 = "test2";
   char* m3 = "test3";
   char* m4 = "test4";
   char* m5 = "test5";

   char* m11 = "test111";
   char* m12 = "test22222";
   char* m13 = "test3333333";
   char* m14 = "test444444444";
   char* m15 = "test55555555555";

   menuList[0] = m1;
   menuList[1] = m2;
   menuList[2] = m3;
   menuList[3] = m4;
   menuList[4] = m5;

   myStruct.stringNum = 0;    //Нулевая строка
   foo(&myStruct);

   menuList[0] = m11;
   menuList[1] = m12;
   menuList[2] = m13;
   menuList[3] = m14;
   menuList[4] = m15;

   myStruct.stringNum = 4;    //Нулевая строка
   foo(&myStruct);

   return EXIT_SUCCESS;
}

Плюс в коде исправил некорректный доступ к строкам на краях массива.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Си: Статический массив указателей на строки
СообщениеДобавлено: 25 июл 2017, 15:49 
Заглядывает иногда

Зарегистрирован: 12 апр 2011, 23:33
Сообщения: 40
Всем спасибо, кажется, все ваши мысли - то, что нужно! Да, про умножение на длину строки я думал, но казалось, что есть какая-то конструкция чуть лучше..
Короче, пора в отпуск :-)

Netzschlange, спасибо за реальный пример!
Некорректный доступ я срезаю в зависимости от необходимости собственными макросами...
Код:
#define CUT_CIRCLE_POINTER(number, maxSize)
#define CUT_POINTER(number, maxSize)

...в зависимости от необходимости зациклить указатель строки или срезать на границах.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Си: Статический массив указателей на строки
СообщениеДобавлено: 26 июл 2017, 01:23 
Старожил
Аватара пользователя

Зарегистрирован: 30 янв 2010, 01:03
Сообщения: 647
Откуда: Херсон
Код:
const u08 __flash *const __flash *ppszListItem; /**Указатель (во Flash) на указатели строк (во Flash) */
u08 *const __flash * ppszListItem_RAM; /**Указатель (во Flash) на указатели строк (в RAM) */

_________________
Если руки золотые, то не важно с какого места они растут.
Изображение
Изображение


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Си: Статический массив указателей на строки
СообщениеДобавлено: 26 июл 2017, 01:54 
Старожил
Аватара пользователя

Зарегистрирован: 30 янв 2010, 01:03
Сообщения: 647
Откуда: Херсон
Код:
/* Длинна строки должна быть 6 печатных знаков */
u08 * const __flash Lst_nSets_Ram[] = {
  "_min_ ",
  "_mid_ ",
  "_max_ ",
  "_usr1_",
  "_usr2_",
  "_usr3_",
  "_usr4_",
  "_usr5_",
};
u08 *const __flash * ppszListItem_RAM;
ppszListItem_RAM = Lst_nSets_Ram;

_________________
Если руки золотые, то не важно с какого места они растут.
Изображение
Изображение


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 11 ] 

Часовой пояс: UTC + 5 часов


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB