#c #pointers #syntax
#c #указатели #синтаксис
Вопрос:
Я просматривал некоторый код из Google, и что-то привлекло мое внимание.
#include <iostream>
using namespace std;
const int kStudents = 25;
const int kProblemSets = 10;
// This function returns the highest grade in the Problem Set array.
int get_high_grade(int *a, int cols, int row, int col) {
int i, j;
int highgrade = *a;
for (i = 0; i < row; i )
for (j = 0; j < col; j )
if (*(a i * cols j) > highgrade) // How does this line work?
highgrade = *(a i*cols j);
return highgrade;
}
main() {
int grades[kStudents][kProblemSets] = {
{750, 700, 85, 720, 84},
{85, 92, 93, 96, 86},
{95, 90, 103, 76, 97},
{65, 62, 73, 84, 73}
};
int std_num = 4;
int ps_num = 5;
int highest;
cout << *(int *)grades << endl;
highest = get_high_grade((int *)grades, kProblemSets, std_num, ps_num);
cout << "The highest problem set score in the class is " << highest << endl;
}
Это было (int *)grades
. Я никогда не видел этого раньше ни в одном учебнике, поэтому это застало меня врасплох. Раньше я cout << *(int *)grades << endl;
определял, что это указатель, но я никогда не видел указатель с таким синтаксисом.
Кто-нибудь может объяснить, как это работает? Спасибо.
Ответ №1:
grades
представляет собой массив массива int
объектов.
Выражение указателя grades
неявно преобразуется в большинстве контекстов в указатель на начальный (0-й) элемент массива, поэтому выражение grades
само по себе имеет тип int(*)[kProblemSets]
, указатель на массив int
.
(int*)
Приведение преобразует это значение указателя из одного типа указателя в другой и *
разыменовывает полученный преобразованный указатель, выдавая int
результат.
Это сомнительно; я не думаю, что есть какая-либо гарантия, что код будет делать то, что вы ожидаете. Если целью является вывод значения первого элемента первой строки массива, просто используйте:
std::cout << grades[0][0] << std::endl;
(Кстати, main()
должно быть int main()
. В C нет «неявного int
правила; вы должны явно указать возвращаемый тип.)
Комментарии:
1. Если вы измените 750 на 70, то
cout << *(int *)grades << endl;
будет выведено 720, т.е. наибольшее значение.2. Я не смотрел на код, который вычисляет наибольшее значение, только
cout << *(int *)grades << endl;
то, о чем вы спрашивали. Когда я меняю750
на70
, этот оператор печатается70
.3. О, мое недоразумение. Извините. Вы правы. Спасибо за разъяснение.
4.
*(int *)grades
гарантированно работает, могут возникнуть споры о том, выполняет ли функция доступ к массиву за пределами (считывание конца первой строки)
Ответ №2:
Поскольку grades — это 2d-массив, при приведении к указателю вы получаете указатель на первый элемент массива. Это то, что делает (int*) . * в начале получает значение указателя, который, как уже было сказано, является первым элементом, который в данном случае имеет значение 750.
Это эквивалентно grades[0][0] .
Комментарии:
1. Когда вы избавитесь от всего кода, просто получите 2d-массив, и
cout << *(int *)grades << endl;
тогда он выдаст ошибку компиляции. И если вы измените положение самого высокого значения в программе, оно выведет его вместо первого.2. @TCG: Вы уверены в этом?
grades
это выражение массива, которое преобразуется в указатель.(int*)
Приведение преобразует его в другой тип указателя, что сомнительно, но законно.*
Разыменовывает результирующий указатель, выдавая результат типаint
. Я не думаю, что поведение четко определено, но оно должно компилироваться. (Компилятор может предупредить об этом, но это не обязательно.)3. Я проверил его без функции
get_high_grade
и последних двух строк кода вmain
функции. Он не компилировался, поскольку выдавал ошибку, вот почему я был так смущен.