arrayscmultidimensional-array

Code to search for combinations of characters in a two-dimensional array doesn't output anything


This code if supposed to first take a line of inputs of combinations of characters each separated by space, then no more than 10 rows of inputs, all of equal length but no longer than 10 characters, then search for the combinations of characters from the first line in the two-dimensional array. This is the code.

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#define WORDNUM 100
#define SIZE 10


int getWords(char wordMatrix[WORDNUM][100]){

    char c;
    int i=0, j=0;

    while ((c=fgetc(stdin)) != '\n'){
        if (isalpha(c)){
            wordMatrix[i][j]=c;
            j++;
        }
        else if(c==' '){
            i++;
            j=0;
        }
    }

    return i+1;
}


int getMatrix( char matrix[SIZE][SIZE]){

    char c;
    int i=0, j;

    while ((c=fgetc(stdin)) != EOF && i < (SIZE)){
        if (isalpha(c)){
            matrix[i][j]=c;
            j++;
        }
        else if(c=='\n'){
            i++;
            j=0;
        }
    }

    return i;
}


int checkExist(int rowM , int xM, int rowNum, int rowLen, char *word, char matrix[SIZE][SIZE]){
    int xW=1;
    int direction;

    direction = -1;
    while((rowM + direction) > 0){
        if(matrix[xM][rowM+direction] == word[xW]){
            xW++;

            if(xW == strlen(word)) return 1;

            else direction--;
            
        }

        else break;
    }

    direction = -1;
    while((xM + direction) > 0){
        if(matrix[xM+direction][rowM] == word[xW]){
            xW++;

            if(xW == strlen(word)) return 1;

            else direction--;
        }

        else break;
    }

    direction = 1;
    while((rowM + direction) < rowNum){
        if(matrix[xM][rowM+direction] == word[xW]){
            xW++;

            if(xW == strlen(word)) return 1;

            else direction++;
        }

        else break;
    }

    direction = 1;
    while((xM + direction) < rowLen ){
        if(matrix[xM+direction][rowM] == word[xW]){
            xW++;
            
            if(xW == strlen(word)) return 1;

            else direction++;
        }

        else break;
    }

    return 0;
}


int checkMatrix(int rowNum, int rowLen, char *word, char matrix[SIZE][SIZE]){

    int xM, rowM, check;

    for(rowM=0; rowM < rowNum; rowM++){
        for(xM=0; xM < rowLen; xM++){
            if(word[0] == matrix[rowM][xM]){
                if(strlen(word) == 1) return 1;
                else if (strlen(word)>1 && (check = checkExist(rowM, xM, rowNum, rowLen, word, matrix)) == 1) return 1;
            }
        }
    }

    return 0;
}


int main() {

    char word[WORDNUM][100], matrix[SIZE][SIZE];
    int logRowNumW, logRowNumM, logRowLen, rowW, x, check;

    logRowNumW = getWords(word);

    logRowNumM = getMatrix(matrix);

    logRowLen = strlen(matrix[0]);    

    for(rowW=0; rowW <logRowNumW; rowW++){
        if((check = checkMatrix(logRowNumM, logRowLen, word[rowW], matrix)) == 1){
            for(x=0; x<strlen(word[rowW]); x++){
                printf("%c", word[rowW][x]);
            }
        }
    }

    return 0;
}

Problem is, it doesn't output anything, correct or incorrect, just nothing. Thanks for any and all advice

Edit: As it turns out, two stupid mistakes were at fault. First, xW ins't reset for each direction in checkExist and second, I mixed up xM and rowM in checkExist, it works well now.


Solution

    1. getWords(), getMatrix(): fgetc() returns an int (not a char) and it's particular important when you are checking against EOF in getMatrix().

    2. getWords(), getMatrix(): You don't terminate wordMatrix or matrix with '\0' so anything that relies on those being strings (ie strlen()) will trigger undefined behavior.

    3. getWords() probably should skip leading spaces.

    4. getMatrix() you need to initialize j.

    5. (Not fixed) Introduce a MAX_WORD_LEN or similar for the 2nd 100 magic value, and use that upper bound when you iterate through your matrix to avoid buffer overflow. Or consider using getline() to dynamically allocate space for your input.

    6. (Not fixed) Consider using strtok() for parsing your string into words. Note, it changes the input string, it's a little more work but strpbrk() or strch() can be used to locate your delimiter but you do need to handle initial, consecutive and trailing delimiters yourself.

    With those initial 4 changes:

    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <stdlib.h>
    
    #define WORDNUM 100
    #define SIZE 10
    
    int getWords(char wordMatrix[WORDNUM][100]){
        int c;
        int i=0, j=0;
        while ((c=fgetc(stdin)) != '\n') {
            if (isalpha(c)){
                wordMatrix[i][j]=c;
                j++;
            } if(c==' ') {
                if(!j) continue;
                wordMatrix[i][j] = '\0';
                i++;
                j=0;
            }
        }
        wordMatrix[i][j] = '\0';
        return i+1;
    }
    
    
    int getMatrix( char matrix[SIZE][SIZE]){
        int c;
        int i=0, j = 0;
        while ((c=fgetc(stdin)) != EOF && i < (SIZE)){
            if (isalpha(c)){
                matrix[i][j]=c;
                j++;
            }
            else if(c=='\n'){
                matrix[i][j] = '\0';
                i++;
                j=0;
            }
        }
        // If last line can be terminated with EOF instead of \n
        // then you need another '\0':
        // matrix[i][j] = '\0';
        return i;
    }
    
    
    int checkExist(int rowM , int xM, int rowNum, int rowLen, char *word, char matrix[SIZE][SIZE]){
        int xW=1;
        int direction;
    
        direction = -1;
        while((rowM + direction) > 0){
            if(matrix[xM][rowM+direction] == word[xW]){
                xW++;
    
                if(xW == strlen(word)) return 1;
    
                else direction--;
    
            }
    
            else break;
        }
    
        direction = -1;
        while((xM + direction) > 0){
            if(matrix[xM+direction][rowM] == word[xW]){
                xW++;
    
                if(xW == strlen(word)) return 1;
    
                else direction--;
            }
    
            else break;
        }
    
        direction = 1;
        while((rowM + direction) < rowNum){
            if(matrix[xM][rowM+direction] == word[xW]){
                xW++;
    
                if(xW == strlen(word)) return 1;
    
                else direction++;
            }
    
            else break;
        }
    
        direction = 1;
        while((xM + direction) < rowLen ){
            if(matrix[xM+direction][rowM] == word[xW]){
                xW++;
                if(xW == strlen(word)) return 1;
                else direction++;
            }
            else break;
        }
        return 0;
    }
    
    
    int checkMatrix(int rowNum, int rowLen, char *word, char matrix[SIZE][SIZE]){
        for(int rowM=0; rowM < rowNum; rowM++){
            for(int xM=0; xM < rowLen; xM++){
                if(word[0] == matrix[rowM][xM]){
                    if(strlen(word) == 1) return 1;
                    else if (strlen(word)>1 && (checkExist(rowM, xM, rowNum, rowLen, word, matrix) == 1)) return 1;
                }
            }
        }
        return 0;
    }
    
    
    int main() {
        char word[WORDNUM][100], matrix[SIZE][SIZE];
        int logRowNumW = getWords(word);
        int logRowNumM = getMatrix(matrix);
        int logRowLen = strlen(matrix[0]);
        for(int rowW=0; rowW <logRowNumW; rowW++){
            if((checkMatrix(logRowNumM, logRowLen, word[rowW], matrix)) == 1){
                for(int x=0; x<strlen(word[rowW]); x++){
                    printf("%c", word[rowW][x]);
                }
            }
        }
        return 0;
    }
    

    Your program now generates output:

    a
    ab
    cd
    <EOF>
    a
    

    Using the supplied input (I think) in comment here is how I would write a hard-coded test case and revise the code along the lines discussed in the comments to my answer:

    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <stdlib.h>
    
    #define N 10
    #define NORTH {-1, 0}
    #define EAST {0, 1}
    #define SOUTH {1, 0}
    #define WEST {0, -1}
    
    int checkExist(int r, int c, int m, int n, const char *word, const char matrix[][N]) {
        if(word[0] != matrix[r][c])
            return 0;
        const int directions[][2] = { NORTH, EAST, SOUTH, WEST };
        for(int d = 0; d < sizeof directions / sizeof *directions; d++) {
            int w = 1;
            for(int r2 = r + directions[d][0], c2 = c + directions[d][1]; r2 >= 0 && r2 < m && c2 >= 0 && c2 < n && word[w]; r2 += directions[d][0], c2 += directions[d][1], w++)
                if(word[w] != matrix[r2][c2])
                    break;
            if(!word[w])
                return 1;
        }
        return 0;
    }
    
    int checkMatrix(int m, int n, const char *word, const char matrix[][N]){
        for(int r=0; r < m; r++)
            for(int c=0; c < n; c++)
                if(checkExist(r, c, m, n, word, matrix))
                    return 1;
        return 0;
    }
    
    int main(void) {
        char *word[] = {
            "oh",
            "to",
            "lot",
            "kol",
            "lok",
            "tol",
            "mol",
            "ho",
            "jol",
            "loj",
            "lol"
        };
        int words = sizeof word / sizeof *word;
        char matrix[][N] = {
            "john",
            "moto",
            "tolo"
        };
        int m = sizeof matrix / sizeof *matrix;
        int n = strlen(matrix[0]);
        for(int w=0; w < words; w++)
            if((checkMatrix(m, n, word[w], matrix)))
                printf("%s\n", word[w]);
    }
    

    and this non-interactive program returns:

    oh
    to
    lot
    tol
    ho
    

    which I believe is the correct output.

    If word[w] matches then reverse(word[w]) would, too. You could pre-process word into an array of struct { char *word, int has_reverse }, so in the above { "oh", 1 }, { "to", 0 }, .... If the word matches you also print out the reverse if has_reverse is true.