Странный синтаксис указателя

#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 функции. Он не компилировался, поскольку выдавал ошибку, вот почему я был так смущен.