Как инициализировать довольно сложный массив символов в C? - PullRequest
0 голосов
/ 12 октября 2008

Предполагая Visual C / C ++ 6, у меня есть сложная структура данных из 22399 элементов, которая выглядит следующим образом:

{
{ "(SAME", "AS", "U+4E18)", "HILLOCK", "OR", "MOUND"},
{ "TO", "LICK;", {1, 1, 0}, "TASTE,", "A", "MAT,", "BAMBOO", "BARK"},
{ "(J)", "NON-STANDARD", "FORM", "OF", "U+559C", ",", {1, 1, 0}, "LIKE,", "LOVE,", "ENJOY;", {1, 1, 4}, "JOYFUL", "THING"},
{ "(AN", "ANCIENT", {1, 2, 2}, {1, 2, 3}, "U+4E94)", "FIVE"}, 
...
}

Какой лучший способ заявить об этом? Я пробовал такие вещи, как

char * abbrevs3[22399][] = { ... };

и

char * abbrevs3[22399][][] = { ... };

но компилирует что-то хроническое.

РЕДАКТИРОВАТЬ : Данные представляют собой базу данных описаний определенных символов Unihan. Я изучал различные способы сжатия данных. В его нынешнем виде у вас есть 22399 записей, каждая из которых может содержать различное количество строк или триплетов {маркер сокращения, строка, где последний раз видели, элемент этой строки, где последний раз видели}.

Кстати, Грег говорит, что мне может потребоваться, чтобы каждая строка содержала одинаковое количество элементов, даже если некоторые из них являются пустыми строками. Это тот случай?

РЕДАКТИРОВАТЬ # 2 : И мне приходит в голову, что некоторые числовые значения в триплетах выходят далеко за пределы char.

Ответы [ 6 ]

4 голосов
/ 12 октября 2008

Я хотел бы изучить хранение данных в XML или какой-либо другой структурированной форме, а затем прочитать и проанализировать их вместо инициализации в коде. Штраф, который вы платите при инициализации, будет более чем компенсирован за простоту понимания и повышение удобства сопровождения вашего кода. Я также подумал бы о разработке конкретной структуры данных для хранения каждой записи.

[РЕДАКТИРОВАТЬ] В приведенном ниже примере пытается повторить ваше последующее описание:

enum EntryType { string = 0, triple = 1 };

typedef struct {
   enum EntryType entry_type;
   union {
      char** string;
      int[3] *triple;
   }
} Entry;

typedef struct {
   Entry *entries;
} Abbreviation;

Abbreviation *abbrevs3;

abbrevs3 = parseAbbreviationData("path-to-abbreviations/abbrevs.xml");
3 голосов
/ 12 октября 2008

В C вы можете не указывать размер first при объявлении массива:

char * abbrevs3[][22399] = { ... };

Это потому, что компилятор хочет знать, насколько велика каждая «строка», чтобы он мог правильно расставить «столбцы». Я помещаю размеры в кавычки, потому что вы можете интерпретировать размеры любым способом, каким пожелаете, но это обычное соглашение для двумерного массива.

Тем не менее, неясно, какова ваша структура данных на самом деле или для чего вы пытаетесь ее инициализировать. Кажется, что у ваших данных образца нет какого-либо паттерна.

2 голосов
/ 13 октября 2008

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

Перефразируя вопрос, в строке 4 исходного примера:

{ "(AN", "ANCIENT", {1, 2, 2}, {1, 2, 3}, "U+4E94)", "FIVE"},

Вы хотите перевести тройки в ссылки на строки, которые использовались ранее, в попытке сжать данные. Эта строка становится:

{ "(AN", "ANCIENT", "FORM", "OF", "U+4E94)", "FIVE"},

Если целью является сжатие, я не думаю, что вы увидите здесь много выигрыша. Тройные самоссылки имеют длину 3 байта, но заменяемые строки имеют всего 8 байтов, считая нулевые терминаторы, и вы сохраняете только 2 байта в этой строке. И это для использования символов. Поскольку ваша структура настолько велика, что вам понадобится использовать целые числа для ссылок, ваша тройка на самом деле составляет 12 байтов, что еще хуже. В этом случае вы когда-нибудь сэкономите место, заменив слова длиной 12 символов или более.

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

Если по какой-то причине это не вариант, я думаю, я бы получил список всех уникальных слов в ваших данных и использовал бы их в качестве справочной таблицы. Затем сохраните все строки в виде списка индексов в этой таблице. Вам придется использовать две таблицы, но в конце концов это может быть проще, и это сэкономит вам пространство, используемое ведущими 1, которые вы используете в качестве «маркера сокращения». По сути, ваши маркеры сокращений станут одним индексом, а не триплетом.

Итак,

const char * words[] = {
    "hello", "world", "goodbye", "cruel"
    };

const int strings[] = {
    { 0, 1 },
    { 2, 3, 1 }
    };

Вы бы все равно потеряли много места, если бы ваши строки не были примерно одинаковой длины.

1 голос
/ 14 октября 2008

Исходные данные составляют около 1,7 МБ, которые были получены из 2 других файлов, один от моего работодателя, а другой (Unihan.txt, около 30 МБ) от Консорциума Unicode. Используя технику поиска в словаре, используя словарь из 128 самых длинных и наиболее часто встречающихся слов, размер данных уменьшается только до 1,5 МБ. Я мог бы, вероятно, улучшить это, проявив большую интеллектуальность при обнаружении слов, которое на данный момент является просто разделением VBScript () в пространстве.

У меня нет данных о том, как мало я получаю с помощью квази-Хаффмана, но я предполагаю, что он немного меньше 1 МБ. Я хотел, чтобы все это было в двоичном, а не в отдельном файле (несмотря на то, что другие могут сказать о дурной практике и т. Д.). Однако в настоящее время все становится слишком сложно, по крайней мере, в C. Если Я могу понять, как создать вариантные массивы BSTR в Euphoria ...

РЕДАКТИРОВАТЬ : Я использовал поиск по словарю в отношении стандартных UCN, и это хорошо работает из-за повторяющейся природы описаний глифов. Проблема с Unihan заключается в том, что в итоге вы получите описание того, что означает глиф ; есть качественная (и количественная!) разница между "VULGAR FRACTION ONE QUARTER" и "A KIND OF PUNISHMENT IN HAN DYNASTY, NAME OF CHESSMEN IN CHINESE CHESS GAME(SIMPLIFIED FORM, A VARIANT U+7F75) TO CURSE; TO REVILE; TO ABUSE, TO SCOLD"

Таким образом, переход от поиска в словаре к более мощной технике «сжатия».

(И до того, как кто-нибудь скажет: «Так в чем же дело с 1,7 МБ?», Я пришел из эпохи, когда 16 КБ ОЗУ было много. И у меня есть ограничения по пространству в любом случае.)

1 голос
/ 12 октября 2008

Я думаю, что вопрос здесь заключается в том, можете ли вы статически объявить многомерный массив строк в стиле C, где в каждой строке содержится разное количество строк. Итак, как-то так:

const char * arr[][3] =
    {
    {"bla", "bla", "bla"},
    {"bla", "bla" }
    };

В некоторых языках это называется «зубчатым массивом». В C и C ++ вы можете сделать это, хотя компилятор захочет выделить место для хранения всех строк, как будто они имеют одинаковую длину, поэтому в итоге вы не инициализируете 3-й элемент второго массива. Когда я проверял это на gcc, для третьего элемента в этом массиве было установлено значение NULL, но я не знаю, можете ли вы рассчитывать на это.

Не думаю, что вы сможете заставить компилятор принимать массивы, объявленные как {1,2,3} как строки в стиле C. Даже если это произойдет, и вы отнесетесь к ним как к строкам, у вас возникнет проблема, поскольку они не заканчиваются нулем.

Я бы согласился с другими авторами, но лучше всего сохранить эти данные в XML, yaml или, возможно, в базе данных, из которой вы их берете, и получить к ней доступ. Если вам нужно создать их статически в исходном файле, вам, вероятно, лучше объявить структуру, которая имеет смысл для ваших данных, и инициализировать их массив. Что-то вроде:

typedef struct
{
  const char * somestring;
  const char * someotherstring;
  const unsigned int triple[3];
} Abbreviation;

const Abbreviation abb[] =
  {
    {"First Thing", "Second String", {1,2,3} },
    {"Other Thing", "Some String", {4,5,6} }
  };
0 голосов
/ 13 октября 2008

Сага еще не закончилась, кажется. В конце концов я превратил все в рваный массив int. Но с этим теряется представление об элементах в строке, от которых зависел самореференциальный механизм триплетов.

Теперь я использую Euphoria , а не C, из-за его превосходной поддержки рваных массивов. Можно создать стандартные библиотеки DLL с помощью Euphoria, и, как только я пойму, как вернуть обратно вариантный массив BSTR и написать Typelib ...

Имейте в виду, я полагаю, я мог бы придерживаться C и хранить триплеты как всего три целых числа подряд и хранить строки как указатели, приведенные к целым числам. И это спасло бы меня от довольно большого переписывания VBScript, который в первую очередь создал самореферентный словарь.

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