Search code examples
c

How to declare a function that returns a char[][]?


I have a program that tries to input a file and read it into RAM using sscanf. However, I haven't even been able to test my logic because my compiler is throwing some errors that I believe all stem from the same mistake (either repeated in multiple places, or one spot failing caused a domino effect)

The problem stems from declaring a 2d array of chars to the heap by using:

char[][] swapKey;

(I'm using cygwin terminal btw)

I try to declare a function that has a return type of the same:

char[][] getKey() {

This throws an error:

swapCode.c:13:5: error: expected identifier or ‘(’ before ‘[’ token
   13 | char[][] getKey() {
      |     ^

This seems like it thinks I didn't finish declaring the "char[][]"?

There are a couple errors of this same genre, so I'm going to include the entire file (only ~50 lines) because I don't know exactly where the issue stems from. I'll also include exactly what the compiler said in response to trying to compile:

#include <stdio.h>

#define SWAP_CODE_KEY "testSwapCodeKey.txt"

int changes;

void printSwapKey (char[][] swapKey) {
    for (int i = 0; i < changes; i++) {
        printf("%c=%c\n", swapKey[0], swapKey[1]);
    }
}

char[][] getKey() {
    FILE *file = fopen(SWAP_CODE_KEY, "r");
    if(file == NULL) {
        return 0;
    }

    char line[5];
    int lines = 0;

    if (sscanf(fgets(line, sizeof(line, file)), "changes=%d", changes) == 1) {
        printf("Succesfully retrieved number of changes from file: %d\n", changes);
    } else {
        printf("Failed to retrieve number of changes from file\n");
        exit(0);
    }
    
    char[changes][1] swapKey;
    for (int i = 0; i < changes; i++) {
        swapKey[i][0] = "";
        swapKey[i][1] = "";
    }
    
    printf("\n");
    while(fgets(line, sizeof line, file) || lines >= changes) {
        lines++;
        char originalCharacter = "";
        char swappedCharacter = "";
        if (sscanf(line, "%c=%c", originalCharacter, swappedCharacter) == 2) {
            printf("Trying to add line to swapKey at line %d\n", lines);
            swapKey[lines][0] = originalCharacter;
            swapKey[lines][1] = swappedCharacter;
            printf("Added line to swapKey at line %d\n", lines);
        } else {
            printf("Failed to scan line at line %d", lines);
            exit(0);
        }
    }
    
    return swapKey;
}

int main(int argc,char *argv[]) {
    char[][] swapKey = getKey();
    printSwapKey (swapKey);
}

And the compiler:


<myName> <myName>Laptop ~
$ cc swapCode.c -Wall
swapCode.c:7:24: error: array type has incomplete element type ‘char[]’
    7 | void printSwapKey (char[][] swapKey) {
      |                        ^
swapCode.c:7:24: note: declaration of multidimensional array must have bounds for all dimensions except the first
swapCode.c:7:29: error: expected ‘;’, ‘,’ or ‘)’ before ‘swapKey’
    7 | void printSwapKey (char[][] swapKey) {
      |                             ^~~~~~~
swapCode.c:13:5: error: expected identifier or ‘(’ before ‘[’ token
   13 | char[][] getKey() {
      |     ^
swapCode.c: In function ‘main’:
swapCode.c:55:9: error: expected identifier or ‘(’ before ‘[’ token
   55 |     char[][] swapKey = getKey();
      |         ^
swapCode.c:56:5: warning: implicit declaration of function ‘printSwapKey’ [-Wimplicit-function-declaration]
   56 |     printSwapKey (swapKey);
      |     ^~~~~~~~~~~~
swapCode.c:56:19: error: ‘swapKey’ undeclared (first use in this function)
   56 |     printSwapKey (swapKey);
      |                   ^~~~~~~
swapCode.c:56:19: note: each undeclared identifier is reported only once for each function it appears in

<myName> <myName>Laptop ~
$

I'm sorry for how vague this question is, but I've spent about 1.3 hours just staring at this and not getting any closer.


Solution

  • Returning an array from a function

    In C, it is not possible to return an array from a function. Therefore, the function declaration

    char[][] getKey() {
    

    is wrong.

    However, it is possible for the calling function to pass a pointer to the start of an array and for the called function to modify the content of the array using that pointer, so that the calling function can then access the new content of the array. For example:

    #include <stdio.h>
    
    void write_array( char *arr, size_t arr_size )
    {
        snprintf( arr, arr_size, "%s", "banana" );
    }
    
    int main( void )
    {
        // make array large enough to store both "apple"
        // and "banana"
        char text[7] = "apple";
    
        printf( "Text before function call: %s\n", text );
        write_array( text, sizeof text );
        printf( "Text  after function call: %s\n", text );
    }
    

    This program will print the following:

    Text before function call: apple
    Text  after function call: banana
    

    Declaring an array without specifying its size

    The line

    char[][] swapKey = getKey();
    

    is incorrect.

    In C, the size of an array cannot be changed after creating the array, so you must specify its size when creating it.

    However, it is permissible to not specify the size of the array if its size is implied by the initializer. For example, if you write

    int arr[] = { 5, 6, 7 };
    

    then the array has a size of 3, because you initialized it with 3 elements.

    But when initializing a 2D array, only the size of the outer array may be implied; the size of the inner array must be explicitly specified. For example:

    int arr[][3] =
    {
        {  5,  6,  7 },
        {  8,  9, 10 },
        { 11, 12, 13 },
        { 14, 15, 16 }
    };
    

    In this case, the size of the outer array is implied to be 4, but the size of the inner array must be explicitly specified to be 3.

    Passing a multidimensional array to a function

    The function declaration

    void printSwapKey (char[][] swapKey) {
    

    is wrong.

    In C, it is not possible to directly pass an array to a function. When a function is declared to take an array as a parameter, the compiler automatically converts the parameter's data type to a pointer to an element of the array.

    For example, in one of the previous sections, I used the following function declaration:

    void write_array( char *arr, size_t size )
    

    I could also have written the following:

    void write_array( char arr[], size_t size )
    

    In this case, the compiler would have automatically converted the char [] parameter to char *. It is not necessary to specify the size of the array, because this information is discarded anyway.

    However, this does not apply to multidimensional arrays. A multidimensional array is nothing else than an array of arrays. If you declare a function to accept a multidimensional array as a parameter, then, as mentioned above, the compiler will automatically convert the parameter to a pointer to an element of the (outer) array. Therefore, the compiler will convert the parameter to a pointer to an (inner) array. For example, if you specify int arr[4][3] as the parameter, then the compiler will convert this parameter to int (*arr)[3] (pointer to array of 3 elements of type int).

    Since only the outer dimension of the multidimensional array is discarded, you can only omit specifying the size of the outer array, but not the size of the inner array. That is why your function declaration is wrong.