Search code examples
cmultidimensional-arrayc-stringsfunction-declarationvariable-length-array

Defining a C function that takes a 2D array with variables for dimension sizes


Edit: Turns out the compiler I'm using doesn't support variable length arrays so I have no way of achieving the notation I desire using MSVC


I have a function which takes in an array of strings and a query string, and returns the index of the string in the array that matches the query.

int findStringIndex(char query[], int strLength, char* strArray, int numStrings) {
    for (int i = 0; i < numStrings; i++) {
        for (int j = 0; j < strLength; j++) {

            // Skip to next word if there is a mismatch
            if (query[j] != *(strArray+ (i * strLength) + j))
                break;

            if (query[j] == '\0' && *(strArray + (i * strLength) + j) == '\0')
                return i;
        }
    }
    return -1;
}

Notably, both the length of the string and the size of the array vary, since I am using this function in several different places with differently sized strings. Currently, this approach has two problems:

  • Ugly array access notation *(strArray+ (i * strLength) + j)) rather than something like strArray[i][j]
  • When I call the function and pass the array of strings as the third argument, I get the warning that the argument I pass "differs in levels of indirection" from char*

Is there a way for me to tell the compiler to accept a variable as the size of one of the array's axes so that I can use the notation strArray[i][j]?

Also, how should I define the function so that I don't get the "levels of indirection" warning?

Edit: As a clarification, the string arrays are not ragged. They have constant sized dimensions, but different arrays that I want to use the function on have different sizes. The code runs fine and achieves the desired behavior in its current state, I just want to make sure I'm writing things the right way

Here are two examples (different string sizes) of arrays I might use with this function:

char instructionStrings[NUM_INSTRUCTIONS][INST_MAX_CHARS] = {
    "nop", "lit", "litn", "copy", "copyl", "asni", /* etc */
};

char typeStrings[NUM_TYPES][TYPE_MAX_CHARS] = {
    "null", "int8", "int16", "int32", "int", "real32", "real"
};

Where INST_MAX_CHARS and TYPE_MAX_CHARS are different values. Then I would call the function like findStringIndex(userInput, TYPE_MAX_CHARS, typeStrings, NUM_TYPES); for the second example


Solution

  • If your compiler supports variable length arrays then the function can be declared and defined the following way as it is shown in the demonstrative program below. Note that not all compilers support variable length arrays (notably MSVC), in which case there is no way to get the desired notation.

    #include <stdio.h>
    #include <string.h>
    
    size_t findStringIndex( size_t m, size_t n, char a[m][n], const char *s ) 
    {
        size_t i = 0;
    
        while ( i < m && !( strcmp( a[i], s ) == 0 ) ) ++i;
        
        return i;
    }
    
    int main(void) 
    {
        enum { M1 = 3, N1 = 10 };
        
        char a1[M1][N1] =
        {
            "Hello", "World", "Everybody"
        };
        
        const char *s = "Hello";
        
        size_t pos = findStringIndex( M1, N1, a1, s );
        
        if ( pos != M1 )
        {
            printf( "\"%s\" is found at position %zu.\n", s, pos );
        }
        else
        {
            printf( "\"%s\" is not found.\n", s );
        }
        
        s = "World";
        
        pos = findStringIndex( M1, N1, a1, s );
        
        if ( pos != M1 )
        {
            printf( "\"%s\" is found at position %zu.\n", s, pos );
        }
        else
        {
            printf( "\"%s\" is not found.\n", s );
        }
        
        s = "Everybody";
        
        pos = findStringIndex( M1, N1, a1, s );
        
        if ( pos != M1 )
        {
            printf( "\"%s\" is found at position %zu.\n", s, pos );
        }
        else
        {
            printf( "\"%s\" is not found.\n", s );
        }
        
        s = "Bye";
        
        pos = findStringIndex( M1, N1, a1, s );
        
        if ( pos != M1 )
        {
            printf( "\"%s\" is found at position %zu.\n", s, pos );
        }
        else
        {
            printf( "\"%s\" is not found.\n", s );
        }
        
        return 0;
    }
    

    The program output is

    "Hello" is found at position 0.
    "World" is found at position 1.
    "Everybody" is found at position 2.
    "Bye" is not found.