Сокращение функции, которая подсчитывает количество уникальных символов в 2D-массиве

#arrays #c #if-statement #c-strings #strchr

#массивы #c #if-оператор #c-строки #strchr

Вопрос:

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

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

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

 bool uniqueChars (Bookcase *b)
{
   int i, j, chars[8] = {0}, cnt = 0;
   char validChars[10] = {"KRGYBMCW."};

   bNullPoint(b);

   for (i = 0; i < b->height; i  ) {
      for (j = 0; j < b->width; j  ) {
         b->shelves[i][j] = toupper(b->shelves[i][j]); /* To aid with testing*/
         if (strchr(validChars, b->shelves[i][j])) {
            if (b->shelves[i][j] == 'K') {
               chars[0]  = 1;
            }
            if (b->shelves[i][j] == 'R') {
               chars[1]  = 1;
            }
            if (b->shelves[i][j] == 'B') {
               chars[2]  = 1;
            }
            if (b->shelves[i][j] == 'G') {
               chars[3]  = 1;
            }
            if (b->shelves[i][j] == 'C') {
               chars[4]  = 1;
            }
            if (b->shelves[i][j] == 'Y') {
               chars[5]  = 1;
            }
            if (b->shelves[i][j] == 'W') {
               chars[6]  = 1;
            }
            if (b->shelves[i][j] == 'M') {
               chars[7]  = 1;
            }
         } else {
            return false;
         }
      }
   }
   for (i = 0; i < 8; i  ) {
      if (chars[i] > 0) {
         cnt  = 1;
      }
   }
   if (cnt > b->height) {
      return false;
   }
   return true;
}
 

Ответ №1:

Объявите массив символов или строковый литерал, например

 const char *letters = "KRBGCYQM.";
 

а затем используйте стандартную строковую функцию strchr , объявленную в заголовке <string.h> , например

 char *p = strchr( letters, b->shelves[i][j] );
if ( p != NULL ) 
{
    if ( b->shelves[i][j] != '.' )   chars[p - letters];
}
else
{
    return false;
}
 

Обратите внимание на то, что читателям вашего кода неясно, почему символ '.' включен, хотя он не учитывается.

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

1. Я продолжал получать stack-buffer-overflow при запуске, но, похоже, это проблема в более широкой программе, поскольку я тестировал ваш метод в меньшем масштабе, и он сработал, так что спасибо!

Ответ №2:

Могу ли я предложить битовые поля вместо массива символов? Что-то вроде этого:-

 present = 0
foreach char c in b->shelves
    if c is a uppercase letter
        present |= 1 << (c - 'A')
present amp;= valid letters bit pattern (this is a constant and is the or of 1 shifted by each letter)
return number of bits in present <= b->height
 

В качестве альтернативы, если вам это не нравится, используйте переключатель, а не последовательность тестов if:-

 switch b->shelves[i][j]
    case 'K'
          chars[0]
    other cases for the valid letters
          chars[whatever]
    default:
        error - an invalid character
 

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

1. Могу ли я предложить битовые поля … почему? Вы не можете использовать битовые поля для подсчета.

2. Мы еще не рассматривали битовые поля или побитовые операторы, поэтому я мог бы попытаться реализовать это, просто чтобы опередить события, спасибо за идею

3. @AndrewHenle: Ну, в примере кода, хотя для каждой буквы есть счетчик, выполняется единственный тест на ненулевое значение, так зачем считать? Битовое поле работает так же хорошо и использует меньше памяти (хорошо, несколько байт, но оно предоставит дополнительный инструмент в наборе трюков OPS, поскольку OP, похоже, учится в данный момент). Затем вы можете И поле для проверки на наличие недопустимых записей, и довольно легко подсчитать количество установленных битов.