Сложная инициализация массива

#c

#c

Вопрос:

На C (НЕ C ) я пытаюсь создать две таблицы строк, которые содержат одинаковые значения, но имеют значения, отсортированные двумя разными способами. И я не хочу, чтобы строки дублировались в памяти.

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

 static const char * monthNames[] = {
  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};


/******** 
 * Month table sorted for O(log N) string lookup
 */
static const char * monthSortedKeys[]= {
  monthNames[3],          /* Apr */
  monthNames[7],          /* Aug */
  monthNames[11],         /* Dec */
  monthNames[1],          /* Feb */
  monthNames[0],          /* Jan */
  monthNames[6],          /* Jul */
  monthNames[5],          /* Jun */
  monthNames[2],          /* Mar */
  monthNames[4],          /* May */
  monthNames[10],         /* Nov */
  monthNames[9],          /* Oct */
  monthNames[8]           /* Sep */
};
  

Разъяснение:Я знаю, как это сделать с помощью цикла. Я пытаюсь выяснить, как это сделать во время компиляции.

Еще одно обновление: я только что скомпилировал это как C (g ), и это работает. Но опять же, я ищу ответ на C.

Комментарии:

1. О, ну, компилятор должен оптимизировать его, чтобы делать то, что вы хотите

2. @K-ballo 1 за юмор. И я только что проверил эту теорию, и она работает. И я думал, что так и будет. Но я надеялся найти способ сделать это явно. В системе с объемом ПЗУ всего 256 КБ (и меньшим объемом оперативной памяти) приятно сразу понять, что ваш код не тратит впустую ПЗУ.

Ответ №1:

Пример фрагмента кода:

 static const char
    JAN[] = "Jan",
    FEB[] = "Feb",
    // ...
    DEC[] = "Dec";

static const char *const monthNames[] = {
  JAN, FEB, /* ... */ DEC
};

static const char *const monthSortedKeys[]= {
    /* APR, ... */ DEC, /* ... */ FEB, JAN /* ... SEP */
};
  

Комментарии:

1. Мне нужно что-то подобное, но я передаю массив строк как argv в main (раньше был main , теперь переименован) функцию. const Определитель предотвратит совпадение в прототипе функции.

Ответ №2:

Кажется, это работает для меня:

 static const char monthNames[][4] = ...
  

Я бы подумал, что объявление указателей как констант помогло бы, но, как указывали другие, это не так.

Комментарии:

1. хороший вариант — об этом не подумал; хотя мое решение все еще может быть более читабельным…

2. Закрыть…. за исключением того, что она ломается sizeof() . Это одно тонкое различие между static const char * array[] и static const char array[][] . Первая приведет к тому, что sizeof() вернет количество указателей в массиве. Вторая приведет к тому, что sizeof() вернет размер 2D-массива.

3. что касается того, почему это работает, а не исходный код: в коде Брайана monthNames[3] необходимо фактически вычислять *(monthNames 3) , т. Е. считывать значение из памяти, тогда как в вашем коде это эквивалентно (char *)(monthNames 3) — доступ к памяти не требуется, просто некоторая арифметика указателя

4. @Brian: на самом деле это не должно иметь значения — следующее все равно будет выполнено: sizeof monthNames / sizeof *monthNames == sizeof monthSortedKeys / sizeof *monthSortedKeys

5. @Christoph Я полагаю, что это хороший момент, поскольку я использую sizeof() для получения количества строк в таблице. Однако я думаю, что ваш ответ, вероятно, в целом предпочтительнее, поскольку он может быть расширен для работы с различными длинами строк. Единственным недостатком является то, что это немного более подробно, чем должно быть.