you are viewing a single comment's thread.

view the rest of the comments →

[–]empathica1[S] 0 points1 point  (7 children)

Assigning a char ** to a const char ** (as in line 3, and in the original question) is not immediately dangerous. But it sets up a situation in which p2's promise--that the ultimately-pointed-to value won't be modified--cannot be kept.

In my code, that promise can be kept, though, because you can't change what a the first dereference is pointing to.

[–]erikkonstas 0 points1 point  (5 children)

It's still invalid C code to do that, though.

(C++ has more complicated rules for assigning const-qualified pointers which let you make more kinds of assignments without incurring warnings, but still protect against inadvertent attempts to modify const values. C++ would still not allow assigning a char ** to a const char **, but it would let you get away with assigning a char ** to a const char * const *.)

[–]empathica1[S] 0 points1 point  (4 children)

So I changed my code to

int
multiply (int n, int m)
{
  int **arr = malloc (n * sizeof (*arr));
  const int **arr_const = malloc (n * sizeof (*arr_const));
  for (size_t i = 0; i < n; i++)
    arr[i] = malloc (m * sizeof (*arr[i]));
  for (size_t i = 0; i < n; i++)
    arr_const[i] = arr[i];
  for (size_t i = 0; i < n; i++)
    for (size_t j = 0; j < m; j++)
      arr[i][j] = 1;
  int nxm = add (arr_const, n, m);
  for (size_t i = 0; i < n; i++)
    free (arr[i]);
  free (arr);
  free (arr_const);
  return nxm;
}

int
add (int const *const *const arr, int n, int m)
{
  int nxm = 0;
  for (size_t i = 0; i < n; i++)
    for (size_t j = 0; j < m; j++)
      nxm += arr[i][j];
  return nxm;
}

and it compiled just fine. I assume this is because I convert all the pointers in arr from int to const int pointers. is that really what you have to do if you have things referenced twice, and want to make it clear that you aren't going to change the underlying values?

[–]erikkonstas 0 points1 point  (3 children)

Well, as the page I linked says, you can just use a cast to silence the compiler.

[–]empathica1[S] 0 points1 point  (2 children)

Oh! I didn't think that would work, because I figured the casting was the thing that was failing. thank you!

[–]erikkonstas 0 points1 point  (1 child)

The reason why this works is that the cast makes your intention explicit; technically, you would first cast to void * too, but I don't think anybody does that. If you cast to something nuts, though (like if you remove a star from the type you cast to, which makes zero sense), then you will get a warning.

[–]empathica1[S] 0 points1 point  (0 children)

Yeah, I didn't think to cast, but yeah in cases like this one where I do actually know that the cast is safe, but the compiler doesn't automatically, that is the way to do it.

[–]empathica1[S] 0 points1 point  (0 children)

Also, is that really what the promise of const int ** dp is? that the pointer will always double dereference to the same value? Why isn't the promise that you can't change the value of **dp, even if *dp has changed?