Матрицы и указатели
По аналогии с одномерными массивами посредством указателей можно работать и с многомерными массивами и, в частности, с двумерными или матрицами. Рассмотрим, как связаны матрицы и указатели на следующем примере:
float matrix[20][10];
Для определенности положим, что первый индекс отвечает за строки матрицы, а второй – за столбцы. Таким образом, в нашей матрице 20 строк и 10 столбцов.
Вспомним, что имя массива – это указатель на его первый элемент. Таким образом, matrix является указателем на первый элемент нашего массива. Однако поскольку двумерный массив – это массив, элементами которого являются массивы, то получаем, что *matrix – это массив из десяти элементов, обратиться к которому по-другому можно так: matrix[0]. По нашему соглашению – это первая строка матрицы.
Теперь, рассматривая этот одномерный массив, можно также заметить, что и его имя является указателем на его первый элемент, поэтому записи matrix[0][0], *matrix[0], (*matrix)[0]) и **matrix, эквивалентны и представляют собой обращение к элементу матрицы, имеющему индексы (0,0).
Продолжим рассуждения с целью понимания, как обратиться к элементу с произвольными индексами (i,j). По нашему соглашению – это элемент, расположенный в строке с индексом i и в столбце с индексом j. Стандартный способ, который был изучен в теме, посвященной массивам, – это matrix[i][j]. Взяв строку по индексу и указатель на элемент в ней, получим запись *(matrix[i]+j). Указатель на строку и индекс столбца даст (*(matrix+i))[j], а при обращении только указателями – *(*(matrix+i)+j).
#define N_ROWS 20
#define N_COLS 10
float matrix[N_ROWS][N_COLS];
void initArray() {
for (int i=0; i<N_ROWS; i++) {
for (int j=0; j<N_COLS; j++) {
*(*(matrix+i)+j) = 100*i + j;
}
}
}
void printArray() {
for (int i=0; i<N_ROWS; i++) {
for (int j=0; j<N_COLS; j++) {
printf("%7.1f", *(*(matrix+i)+j));
}
printf("\n");
}
}
int main() {
initArray();
printArray();
return 0;
}
Обработка матрицы при помощи указателей
Рассмотрим следующую задачу. Требуется написать функцию, которая принимает два аргумента: указатель на квадратную матрицу и ее размер. Функция должна вычислить сумму элементов, расположенных на побочной диагонали.
Указатели на функции
Рассмотрим функцию, которая вычисляет сумму элементов массива:
Эта функция принимает массив в качестве аргумента и, передавая в нее разные массивы, мы можем вычислить для них сумму. Массив в данном случае является переменной, а функция суммирования – постоянная. Рассмотрим теперь ситуацию с точностью до наоборот – массив является постоянным, а функция, которая вычисляется от каждого элемента – переменной. Задача заключается в следующем: для одного массива нужно вычислить
Сумму элементов (сумму первых степеней),
Сумму квадратов элементов (сумму вторых степеней)
Сумму кубов элементов (сумму третьих степеней).
int result = 0;
for (int i=0; i<N; i++) {
result += f(numbers[i]);
}
#define N 7
int numbers[N] = {1,2,3,4,5,6,7};
int calculate(int (*operation)(int)) {
int result = 0;
for (int i=0; i<N; i++) {
result += (*operation)(numbers[i]);
}
return result;
}
int linear(int x) {
return x;
}
int square(int x) {
return x*x;
}
int cube(int x) {
return x*x*x;
}
cout << calculate(linear) << endl;
cout << calculate(square) << endl;
cout << calculate(cube) << endl;
Рассмотрим функцию, которая принимает два аргумента и возвращает их сумму:
int getSum(int a, int b) {
return a+b;
}
В этой функции аргументы a и b являются переменными, а операция суммы – постоянная, другими словами, передавая различные аргументы, мы всегда вычисляем именно сумму. Теперь попробуем поменять их местами – зафиксируем значения a и b, а менять будем операцию. Например, если взять a=10 и b=5, то получив аргумент «сложение», функция вернет 15; получив аргумент «умножение», функция вернет 50; аргумент «деление» даст результат 2; аргумент «вычитание» приведет к результату 5. Вопрос заключается в том, как передать в функцию не переменную, а операцию. Сделать это можно при помощи указателей на функции. Давайте определим значения a и b как константы:
const int a = 10;
const int b = 5;
затем реализуем четыре функции, которые отвечают за операции сложения, деления, умножения и вычитания:
int summarize(int x, int y) {
return x+y;
}
int multiply(int x, int y) {
return x*y;
}
int divide(int x, int y) {
return x/y;
}
int subtract(int x, int y) {
return x-y;
}
Пока все понятно, и нет ничего нового. Теперь реализуем функцию, которая принимает один аргумент – операцию. В нашем примере операция – это одна из четырех функций:
int getResult(int (*operation)(int,int)) {
return (*operation)(A,B);
}
Для вызова этой функции нужно передать название функции, которое является указателем на функцию (аналогично массивам), и функция вернет нам результат этой операции над числами 10 и 5:
printf("Сумма=%d\n", getResult(summarize));
printf("Произведение=%d\n",getResult(multiply));
printf("Частное=%d\n", getResult(divide));
printf("Разность=%d\n", getResult(subtract));
Рассмотрим следующую задачу. Требуется реализовать меню, содержащее несколько пунктов:
вычислить сумму элементов массива;
вычислить сумму квадратов элементов массива;
вычислить сумму кубов элементов массива;