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