1

I'm trying to write a program where you have to find the maximum and minimum number in a multidimensional array using double pointers. But when I try to compile it, the compiler returns to me this message:

warning: passing argument 1 of 'MinMax' from incompatible pointer type [-Wincompatible-pointer-types]
   33 |     MinMax(V, ptm, ptM);
      |            ^
      |            |
      |            double (*)[5]

.\1-maxminarraymulti.c:18:22: note: expected 'double **' but argument is of type 'double (*)[5]'
   18 | void MinMax(double **V, double **mi, double **Ma);".

Code:

#include <stdio.h>

#define N 5
#define M 5

void MinMax(double **V, double **mi, double **Ma);

void main() {
    double V[N][M] = { { 1, 5, 2, 3, 9 },
                       { 12, 6, 90, 2, 0 },
                       { -12, 41, 2, 9, 56 },
                       { 78, 2, 1, 523, 39 }, 
                       { 92, 13, 63, 2, 12 } };

    double Min, Max;

    double *ptMin = &Min;
    double *ptMax = &Max;

    double **ptm = &ptMin;
    double **ptM = &ptMax;
    
    MinMax(V, ptm, ptM);
}

void MinMax(double **V, double **mi, double **Ma) {
    
    //printf to see if the bi-dimensional array has been passed correctly to function.
    printf("%lf", V[3][0]);
}
4
  • void MinMax(double (*V)[M], double **mi, double **Ma) or void MinMax(double V[N][M], double **mi, double **Ma) Commented Jul 14, 2022 at 16:02
  • 1
    You can use variable length array parameters: void MinMax(size_t n, size_t m, double V[][m], double **mi, double **Ma). Call it as MinMax(N, M, V, ptm, ptM); or MinMax(N, M, V, &ptMin, &ptMax);. Commented Jul 14, 2022 at 16:06
  • 2
    You have a true 2D array. But, [dereferencing] double pointers in subfunctions is only valid if you used a a 1D array array of pointers to 1D arrays of double (not what you want to do). See my recent answer: lower triangular matrix You can do: void MinMax(double V[N][M],double *min,double *max) and call it (in main) with: MinMax(V,&Min,&Max); Commented Jul 14, 2022 at 16:08
  • arrays are not simply pointers, and cannot be passed as if they were to functions Commented Jul 14, 2022 at 16:24

2 Answers 2

4

The prototype for your function should be different: it should take a matrix of N by M doubles and pointers to double for the results. The matrix should be const qualified since the function does not modify it.

You could write this as:

void MinMax(double const V[N][M], double *minp, double *maxp);

This prototype is somewhat confusing because arrays are not passed by value: they decay as pointers to their first element, so the array V defined as double V[N][M] is passed to MinMax as a pointer to its first element, a pointer to arrays of M double with type double (*V)[M]. This conversion is implicit and the function prototype applies is implicitly as well, leading to surprising results such as `sizeof(V) == sizeof(double (*)[M]), which is the size of a pointer, not the size of the array, nevertheless that on the matrix. The above definition is equivalent to:

void MinMax(double const (*V)[M], double *minp, double *maxp);

or

void MinMax(double const V[][M], double *minp, double *maxp);

Note that neither of the above prototypes specify the number of rows in the matrix, hence the function can be called with matrices of any number of rows. Either the number is a convention, as double const V[N][M] may imply, or the actual number can be passed as an argument:

void MinMax(int rows, double const V[][M], double *minp, double *maxp);

Unlike previous versions where the second and subsequent dimentions must be known at compile time, C99 allows the matrix size to be specified as variables:

void MinMax(int rows, int cols, double const V[rows][cols],
            double *minp, double *maxp);

Which is still equivalent to:

void MinMax(int rows, int cols, double const V[][cols],
            double *minp, double *maxp);

and

void MinMax(int rows, int cols, double const (*V)[cols],
            double *minp, double *maxp);

Here is a modified version with an C89 implementation of MinMax for a fixed matrix size:

#include <stdio.h>

#define N 5
#define M 5

void MinMax(double const V[N][M], double *minp, double *maxp);

int main() {
    double V[N][M] = { { 1, 5, 2, 3, 9 },
                       { 12, 6, 90, 2, 0 },
                       { -12, 41, 2, 9, 56 },
                       { 78, 2, 1, 523, 39 }, 
                       { 92, 13, 63, 2, 12 } };
    double Min, Max;
    
    MinMax(V, &Min, &Max);
    printf("min=%g, max=%g\n", Min, Max);
    return 0;
}

void MinMax(double const V[N][M], double *minp, double *maxp) {
    double min = V[0][0];
    double max = V[0][0];
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (min > V[i][j])
                min = V[i][j];
            if (max < V[i][j])
                max = V[i][j];
        }
    }
    *minp = min;
    *maxp = max;
}

Output:

min=-12, max=523

Here is a C99 version where the matrix size is specified dynamically:

#include <stdio.h>

void MinMax(int N, int M, double const V[N][M],
            double *minp, double *maxp);

int main() {
    double V[][5] = { { 1, 5, 2, 3, 9 },
                      { 12, 6, 90, 2, 0 },
                      { -12, 41, 2, 9, 56 },
                      { 78, 2, 1, 523, 39 }, 
                      { 92, 13, 63, 2, 12 } };
    double Min, Max;
    int rows = sizeof(V) / sizeof(V[0]);
    int cols = sizeof(V[0]) / sizeof(V[0][0]);
    
    MinMax(rows, cols, V, &Min, &Max);
    printf("min=%g, max=%g\n", Min, Max);
    return 0;
}

void MinMax(int N, int M, double const V[N][M],
            double *minp, double *maxp) {
    double min = V[0][0];
    double max = V[0][0];
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (min > V[i][j])
                min = V[i][j];
            if (max < V[i][j])
                max = V[i][j];
        }
    }
    *minp = min;
    *maxp = max;
}

Output:

min=-12, max=523

To handle arbitrary large matrices, rows, cols, i and j should be defined with type size_t

Note that for this problem, you could just consider the matrix as an array of rows * cols double and pass the count of elements and a pointer to the first element of the first row, an approach that does not require C99 VLA syntax:

#include <stdio.h>

void MinMax(size_t count, double const *V, double *minp, double *maxp);

int main() {
    double V[][5] = { { 1, 5, 2, 3, 9 },
                      { 12, 6, 90, 2, 0 },
                      { -12, 41, 2, 9, 56 },
                      { 78, 2, 1, 523, 39 },
                      { 92, 13, 63, 2, 12 } };
    double Min, Max;
    int rows = sizeof(V) / sizeof(V[0]);
    int cols = sizeof(V[0]) / sizeof(V[0][0]);

    MinMax(rows * cols, &V[0][0], &Min, &Max);
    printf("min=%g, max=%g\n", Min, Max);
    return 0;
}

void MinMax(size_t count, double const *V, double *minp, double *maxp) {
    double min = V[0];
    double max = V[0];
    for (size_t i = 0; i < count; i++) {
        if (min > V[i])
            min = V[i];
        if (max < V[i])
            max = V[i];
    }
    *minp = min;
    *maxp = max;
}

Output:

min=-12, max=523
Sign up to request clarification or add additional context in comments.

3 Comments

as far as I understood from his question he wants pointer to the cell holding min and max value
@0___________: I beg to differ: double *ptMin = &Min; seems to indicate the results are expected to go into Min and Max, but I could be wrong. The way matrices get passed as function arguments is tricky and adds the confusion regarding arrays and pointers. Inexperienced C programmers must master these concepts to understand what is going on, a non trivial achievement for those coming from more modern languages.
It was just my suggestion
2

I would use VLAs - you can pass any size array, not only with defined compile time sizes

The function assumes that you want to get pointers to cells holding max and min value

void MinMax(const size_t rows, const size_t cols, const double (*V)[cols], const double **minp, const double **maxp) 
{
    *minp = &V[0][0];
    *maxp = &V[0][0];
    for (size_t row = 0; row < rows; row++) 
    {
        for (size_t col = 0; col < cols; col++) 
        {
            *minp = V[row][col] < **minp ? &V[row][col] : *minp;
            *maxp = V[row][col] > **maxp ? &V[row][col] : *maxp;
        }
    }
}

VLAs are optional feature but will be not soon :)

6 Comments

VLAs are optional feature but will be not soon... is VLA support mandatory in C2x?
I believe yes, the only problem is how many compilers support it
VLAs are a powerful extension, but they cause so many problems for newbies... The C Standard committee would have been well advised to add slices instead: combinations of pointers and length information to allow the callee to receive the required information by construction for enumeration and bounds checking. The current trend to hack C and C++ to have a larger common subset seems useful mostly for compiler writers, but it does not solve any of the C and C++ problems and complicates the C Standard even further.
@chqrlie VLAs IMO are great and I like this language feature 2. C and C++ are ideologically different and C++ basically does need VLAs
The C2x proposal requires support for VLAs as parameters to functions and dynamic allocation but does not require support for automatic duration VLAs. See N2912 at JTC1/SC22/WG14 for the June 2022 draft of the C2x standard and section §6.10.8.3 Conditional feature macros — __STDC_NO_VLA__: The integer constant 1, intended to indicate that the implementation does not support variable length arrays with automatic storage duration. Parameters declared with variable length array types … Thus, support for such declarations is mandatory.. This is good!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.