简体   繁体   中英

C question regarding pointers in a function

I have two questions regarding this code.

  1. What does the double*** pdata and int*** pmask mean? A pointer to a pointer to a pointer? Why or when is this necessary?

  2. int and double are different types, but are double* and int* also different. Can we operate on them without a cast?

Here's the code I'm puzzled about:

static int makedatamask(int nrows, int ncols, double*** pdata, int*** pmask)
    { int i;
      double** data;
      int** mask;
      data = malloc(nrows*sizeof(double*));
      if(!data) return 0;
      mask = malloc(nrows*sizeof(int*));
      if(!mask)
      { free(data);
        return 0;
      }
      for (i = 0; i < nrows; i++)
      { data[i] = malloc(ncols*sizeof(double));
        if(!data[i]) break;
        mask[i] = malloc(ncols*sizeof(int));
        if(!mask[i])
        { free(data[i]);
          break;
        }
      }
      if (i==nrows) /* break not encountered */
      { *pdata = data;
        *pmask = mask;
        return 1;
      }
      *pdata = NULL;
      *pmask = NULL;
      nrows = i;
      for (i = 0; i < nrows; i++)
      { free(data[i]);
        free(mask[i]);
      }
      free(data);
      free(mask);
      return 0;
    }

Yes - the types are triple pointers or pointers to pointers to pointers. Occasionally they are necessary, but be very scared. In this case, you are allocating two similarly sized 2D arrays, and you have to return the two values by reference, so the triple pointers are necessary, at least while you keep the current function design.

Yes - a double * and an int * are different types; they point to different types. You can do appropriate operations on them without a cast. However, if you are thinking that you can combine the two parallel operations into one, you are probably mistaken.

Your error recovery might be simpler if you created some sub-functions:

static int **alloc_2d_int_array(int nrows, int ncols)
{
    ...
}

static double **alloc_2d_double_array(int nrows, in ncols)
{
    ...
}

Your main allocation function would then simply call these two sequentially. If the second failed, the main allocation function would call the cleanup for the first allocated array. The cleanup code probably needs the relevant size, so you'd probably have:

static void free_2d_double_array(int nrows, double **array)
{
    ...
}

static void free_2d_int_array(int nrows, int **array)
{
    ...
}

These functions might even be visible outside the source (not static ).

You might also consider using a structure to describe the arrays (rows and columns), and the pointers to the arrays. This would allow you to avoid the explicit triple-pointer notation too.

struct double_array
{
    int      nrows;
    int      ncols;
    double **array;
};

Etc.

A) A*** may be a pointer to an array of pointers, or an double dimensional array of pointers
B) int and double are different types and cannot operate without cast

What does the double*** pdata and int*** pmask mean? A pointer to a pointer to a pointer?

Yes.

[When] is this necessary?

When, as this function does, you want to return a pointer-to-pointer value, by pointer. You can also return these by value of course, but this function does it by pointer because it "returns" multiple pointers.

int and double are different types, but are double* and int* also different. Can we operate on them without a cast?

I'm not sure what you mean, but but you can't expect to cast int* to double* or vice versa; int and double most likely have a different representation in memory for the same values (as far as they can represent the same values) and different sizes. You'd also be violating the "strict aliasing" rule of C by saying

double *p = WHATEVER;
int *q = p;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM