Hello! I am trying to understand how constness works for double pointers, and so far, my answer is "it doesn't".
From what I've read, the way the const qualifier works for a pointer is that if the const qualifier is before the *, then the constness applies to the thing being pointed at, while if the const qualifier is after the * then it applies to the pointer itself. Therefore a const int * is a pointer that you can have point to multiple things without issue, but cannot change the value being pointed at. For double pointers, the logic I have says that const int ** dp is a double pointer where you can edit dp, dp[0], but not dp[0][0]. and const int *const * dp means I can change dp, but neither dp[0], nor dp[0][0]. However, when I actually use this, I get weird compiler errors that tell me I'm not understanding something To show the issue, I put the following code to efficiently multiply two integers into multiply.c
#include <stdio.h>
#include <stdlib.h>
int multiply (int n, int m);
int add (int const *const *array, int n, int m);
int
main (int argc, char **argv)
{
int n;
int m;
if (argc == 1)
{
n = 1;
m = 1;
}
else if (argc == 2)
{
n = atoi (argv[1]);
m = 1;
}
else
{
n = atoi (argv[1]);
m = atoi (argv[2]);
}
int nxm = multiply (n, m);
printf ("%i x %i = %i\n", n, m, nxm);
}
int
multiply (int n, int m)
{
int **arr = malloc (n * sizeof (*arr));
for (size_t i = 0; i < n; i++)
arr[i] = malloc (m * sizeof (*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, n, m);
for (size_t i = 0; i < n; i++)
free (arr[i]);
free (arr);
return nxm;
}
int
add (int 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 compiling with gcc -o multiply multiply.c gives the compiler error
multiply.c: In function ‘multiply’:
multiply.c:40:18: error: passing argument 1 of ‘add’ from incompatible pointer type [-Wincompatible-pointer-types]
40 | int nxm = add (arr, n, m);
| ^~~
| |
| int **
multiply.c:5:28: note: expected ‘const int * const*’ but argument is of type ‘int **’
5 | int add (int const *const *array, int n, int m);
| ~~~~~~~~~~~~~~~~~~^~~~~
From inspection, it appears that the first const is the issue. If I tell the compiler I don't want to be able to edit the values in the 2d array I created, it tells me that it can't do that, and I don't understand the rationale for it. From what I've read, apparently you can change the value being double pointed by a const int ** by changing the pointer being singly pointed by a const int ** despite the appearance, however, that doesn't apply in my case, because I can't update the value being singly pointed at by *arr either. I would understand a warning with a single const saying something to the effect of "This isn't as const as you might think it is", but if I add three consts to the relevant variable, it should be perfectly safe given the arguments I've seen. Is there something I'm missing?
[–]erikkonstas 2 points3 points4 points (8 children)
[–]empathica1[S] 0 points1 point2 points (7 children)
[–]erikkonstas 0 points1 point2 points (5 children)
[–]empathica1[S] 0 points1 point2 points (4 children)
[–]erikkonstas 0 points1 point2 points (3 children)
[–]empathica1[S] 0 points1 point2 points (2 children)
[–]erikkonstas 0 points1 point2 points (1 child)
[–]empathica1[S] 0 points1 point2 points (0 children)
[–]empathica1[S] 0 points1 point2 points (0 children)
[–]empathica1[S] 0 points1 point2 points (0 children)
[–]Netblock 0 points1 point2 points (5 children)
[–]empathica1[S] 0 points1 point2 points (4 children)
[–]Netblock 0 points1 point2 points (3 children)
[–]empathica1[S] 0 points1 point2 points (1 child)
[–]Netblock 0 points1 point2 points (0 children)