Home > Enterprise >  How to send 2d-array as argument to function that expects 1d-array in C?
How to send 2d-array as argument to function that expects 1d-array in C?

Time:01-10

This is an exercise from the book C Programming: A modern approach by K.N King

"Assume that the following array contains a week's worth of hourly temperature readings, with each row containing the readings for one day: int temperatures[7][24]; Write a statement that uses the search function to search the entire temperatures array for the value 32."

My code below includes my search function from a previous exercise, and main() where I call the function. Search simply processes an array and checks if any element is equal to a supplied argument "key". The solution appears to compile and execute the expected output, it prints "32 was found", or prints nothing if I comment out the assignment temperatures[5][22] = 32;.

Notice how the function takes a 1d array but the exercise is asking to process a 2d array.

I initially tried this solution without the explicit type cast (int*) in the function call, and got this when compiling (I reformatted it a bit):

1 compiler warning: "passing argument 1 of search from incompatible pointer type"

1 note: "expected 'const int *' but argument is of type 'int * [24]'"

Why do the warnings/note appear? If there is an incompatibility, why are they not errors? The type cast to int* removes any compiling issues, but is the solution actually correct/safe or bad C understanding/practice on my part? I understand that the function expects int* but that the 2d array decays to a pointer of type int * [24] without the type cast. Yet the code works in either case, albeit I just had one test case. How could I modify my solution logic to avoid this issue at all? The search function should stay the same though.

#include <stdbool.h>
#include <stdio.h>

bool search(const int a[], int n, int key);

int main(void){

    int temperatures[7][24] = {0};
    temperatures[5][22] = 32;
    bool has32 = search((int*)temperatures, 7 * 24, 32);

    if(has32)
        printf("32 was found");
    return 0;
}

bool search(const int a[], int n, int key){

    const int *p;

    for(p = a; p < a   n; p  )
        if(*p == key)
            return true;
    return false;
}

CodePudding user response:

Pass the address of the first element but it's technically undefined behavior:

bool has32 = search(&temperatures[0][0], 7 * 24, 32);

The better option is to change the prototype of search() to use a VLA:

bool search(size_t rows, size_t cols, const int a[rows][cols], int key) {
    for(size_t r = 0; r < rows; r  )
        for(size_t c = 0; c < cols; c  )
            if(a[r][c] == key)
               return true;
    return false;
}

and call it like this:

    bool has32 = search(
        sizeof(temperatures) / sizeof(*temperatures),
        sizeof(*temperatures) / sizeof(**temperatures),
        temperatures,
        32
    );

CodePudding user response:

If you can change the search() function parameter type, change it to receive 2D array. If you cannot then call the search() in a loop and in each iteration pass the element of 2D array temperatures to search(). The elements of 2D array temperatures are 1D array of type int [24] which can be passed to search().

In main() you should do:

    bool has32 = 0;
    for (int i = 0; i < 7;   i) {
        has32 = search(temperatures[i], 24, 32);
        if (has32) break;
    }

This is perfectly compatible and will not invoke any kind of UB.

Also, instead of using numbers (like 7 and 24), may you give some name to them for better readability, like this

#define ROWS    7
#define COLUMNS 24

Use them in you program when defining array temperatures:

    int temperatures[ROWS][COLUMNS] = {0};

    temperatures[5][22] = 32;

    bool has32 = 0;
    for (int i = 0; i < ROWS;   i) {
        has32 = search(temperatures[i], COLUMNS, 32);
        if (has32) break;
    }
  • Related