Ссылаясь на этот вопрос и особенно принятый ответ лит, мне интересно, почему gcc жалуется на это:
void func(const int (*ip)[3]) {
printf("Value: %d\n", ip[1][1]);
}
int main() {
int i[3][3] = { {0, 1, 2} , {3, 4, 5}, {6, 7, 8} };
func(i);
return 0;
}
Если я исключу const
, компилятор останется на месте. Я что-то не так понял? Я хотел быть уверен, что func
не изменяет мой массив.
РЕДАКТИРОВАТЬ: То же самое происходит, если я определяю тип данных для моей матрицы:
typedef int Array[3][3];
void func(const Array *p) {
printf("Value: %d\n", (*p)[1][1]);
}
int main() {
Array a = { {0, 1, 2}, {3, 4, 5}, {6, 7, 8} };
func(&a);
return 0;
}
Я согласен, такой код не очень в стиле C, больше похож на C ++. В C ++ действительно не было бы проблем, если бы я определил Array как класс, содержащий все поведение матрицы.
class Array {...};
Полагаю, я не очень хорошо понимал концепцию массивов и массивов массивов в C и передачу их функциям. Есть ли просветление?
Заранее спасибо.
EDIT2: Тем временем я немного обдумал эту проблему, и она, кажется, сходится к следующему вопросу: C / C ++ неявно преобразует указатель на int
в указатель на const int
. Таким образом, следующие работы:
func(const int a[]) // aquivalent: func(const int *a)
{ ... }
int main()
{
int b[10];
func(b);
return 0;
}
Но C / C ++ неявно преобразует указатель на массив из n int
s в указатель на массив из n const int
s. Даже если массив из n int
s неявно преобразуется в массив из n const int
s. Этот уровень косвенности в неявном преобразовании не поддерживается. Следующее будет отклонено (по крайней мере, с предупреждением в C):
func(const int a[][n]) // aquivalent: func(const int (*a)[n])
{ ... }
int main()
{
int b[m][n];
func(b);
return 0;
}
Это похоже на проблему, заключающуюся в том, что C ++ неявно преобразует шаблон для типа A в шаблон типа B, даже если A может быть неявно преобразован в B. Два шаблона имеют совершенно разные типы.
Это правильный ответ?