2013-03-28 3 views
2

Это касается C язык программирования.Проблема со строкой конкатенации в C

У меня есть большое количество 2D-массивов (sizes are not fixed). Рассмотрим следующий пример.

bool sym_a[][]={{...},{...},...}; //consider these are initialized properly 
bool sym_b[][]={{...},{...},...}; 
... 
bool sym_z[][]={{...},{...},...}; 
bool sym_0[][]={{...},{...},...}; 
bool sym_1[][]={{...},{...},...}; 
... 
bool sym_9[][]={{...},{...},...}; 
... 

Обратите внимание на соглашение об именах, все имена одинаковы. Изменяется только последний символ имени массива (лучше, если он может быть более одного символа, но это не важно).

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

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

void doStuff(char letter){ 
    switch(letter){ 
     case 'a': 
      sym_a[0][0]=1; //just for demonstration :D 
     break; 
     case 'b': 
      sym_b[0][0]=1; //same thing, only the character 'a' changed to 'b' 
     break; 
     ... 
     case 'z': 
      sym_z[0][0]=1; 
     break; 
     case '0': 
      sym_0[0][0]=1; 
     break; 
     case '1': 
      sym_1[0][0]=1; 
     break; 
     ... 
     ... 
    }  
} 

Но должен быть лучший способ. Если у меня 1000 таких массивов, то мне нужно написать 1000 таких случаев? Для всех случаев контент точно такой же. Изменяется только один символ имени переменной.

Было бы неплохо, если бы что-то вроде конкатенации строк.

#define conc(a,b) a ## b 

conc(sym_,a) Тогда будет представлять sym_a. Но это не может быть прямо применено здесь. Поскольку я не могу передать точную букву в правый аргумент conc(a,b), можно передать только переменную, содержащую нужную букву.

void doStuff(char letter){ 
    conc(sym_,letter)[0][0]=1; 
} 

conc(sym_,letter) дает sym_letter. Но мне нужно конкатенировать sym_ с содержимым символьной переменной letter.

Например, если я звоню doStuff('b');, их следует указать sym_b, а не sym_letter.

Надеюсь мое требование ясно. Эта вещь кажется довольно простой, но я не могу придумать, как избавиться от этого. Обратите внимание, что размеры (количество строк/столбцов) двумерных массивов не фиксированы. В противном случае я мог бы использовать 3D-массив.

Любая мысль оценена.

+0

Зачем вам так много живых переменных 2D все время? – akshay202

+1

Я не думаю, что язык C имеет тип данных bool. Вы можете создать один массив int и сохранить все ваши данные bool, используя оператор сдвига бит. – akshay202

+1

@ akshay202 хорошо, они не «живые» все время (что вы имели в виду?). они похожи, жестко закодированы в программе и рассматриваются только тогда, когда это необходимо. Думаю, это не проблема в любом случае. но вы видите лучший вариант? И приведенный выше код - это то, что я сейчас использую (да, это работает). Но мне нужна простая альтернатива – Anubis

ответ

1

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

Вы можете определить дополнительный статический массив, который сопоставляет символьный код массиву.

static const struct { 
    char* lookup_code; 
    bool **array; 
} char_code_lookup[] = { 
    { .lookup_code = "a", sym_a }, 
    { .lookup_code = "b", sym_b }, 
    /* ... */ 
    { .lookup_code = NULL, NULL }, /* Terminator */ 
}; 

doStuff Ваша функция может затем сканировать массив ищет соответствующий код поиска, чтобы соответствовать с статически определенным массивом.

С малой магией вы можете сгенерировать как статические массивы, так и статический массив поиска, чтобы уменьшить дублирование, но описанный выше подход, вероятно, легче читать.

В качестве альтернативы вы можете динамически распределять свои массивы с помощью malloc и в то же время связывать код поиска во время создания массива во время выполнения.

+0

Если на самом деле '1000' таких массивов (подразумевая широкие символы), как написано, это может быть немного медленным. Может ли «qsort» разрешить двоичный поиск или, скорее, немного изменить дизайн, чтобы позволить прямой скачок (в зависимости от деталей кодов поиска). – Keith

+0

Правда, такая реализация будет медленной. Как показано, для каждого кода поиска будет существовать 'strcmp', пока не будет найдено совпадение. Улучшенный дизайн может динамически распределять массивы и связывать ключ поиска с хэш-значением, позволяя поиск хэш-вывода O (1). –

1

Что-то вроде этого поможет? [Извиняется, если здесь есть C++. ]

bool** sym_a; 
bool** sym_b ; 
bool** sym_z; 
bool** sym_0; 
bool** sym_1; 
bool** sym_9 ; 


unsigned lowestEntry = 'a'; 
unsigned highestEntry = '9'; 
const unsigned numEntries = highestEntry - lowestEntry; 

size_t size = sizeof(bool**)* numEntries; 

bool*** lookup = (bool***)malloc(size); 

#define conc(a,b) a ## b 
#define index(a) #a[0]-'a' 
#define add(a) lookup[index(a)] = conc(sym_,a) 

void init() 
{ 
    memset(lookup, 0, size); 
    add(a); 
    add(b); 
    add(z); 
    add(9); 
    add(k); // does not compile, sym_k not defined. 
} 

bool** findSymbolTable(char val) 
{ 
    return lookup[val - lowestEntry]; 
} 
1

Выделите большой массив int и разделите его на другие переменные.

например.

данные int [2600];

будет иметь первые 100 целых чисел для sym_a next 100 для sym_b и т. Д. Вы сможете хранить 8 * 100 * 4 булевых значений в этих массивах.

теперь доступ sym_p [х] [у] Вы говорите, у вас есть общие строки R и столбцы C:

INT * старт = данные + (ASCIValue (р) - ASCIValue (а)) * 100 ;

С момента запуска вам необходимо прочитать/записать номер бит (C * x + y).

Смежные вопросы