arrayscif-statementc-stringsstrchr

Shortening a function that counts the number of unique chars in a 2D array


I have a function that counts the number of unique characters in a 2D array by looping over it and increasing the count in each cell of a 1D array by 1 each time a character from the valid char array is found. I then loop over the 1D array and each time a cell with a number higher than 0 is found, a counter is increased. If this number is higher than the height/width of my structure, it returns false.

'.' represents an empty space and whilst it is valid in the scheme of the program, it should not count as a unique character.

I was wondering if there was a way to create a function with the same functionality, but much shorter.

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;
}

Solution

  • Declare a character array or a string literal as for example

    const char *letters = "KRBGCYQM.";
    

    and then use the standard string function strchr declared in the header <string.h> like

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

    Pay attention to that it is unclear for readers of your code why the character '.' is included though it is not counted.