Чаще всего указатели необходимы при работе с функциями.
Аргументы при вызове функции копируются в параметры, и, если требуется получить измененное значение, то такой аргумент нужно передать через указатель. При вызове функции scanf перед каждым вводимой переменной нужно написать ``&``, т.е. передать указатель на переменную, а не её текущее значение.
Наличие ``&`` перед аргументом обычно означает, переменная изменяется в вызываемой функции.
```run-c
#include <stdio.h>
int dx=1, dy=-1;
void move(int* x, int* y) { // изменение координат
*x+=dx;
*y+=dy;
}
void input(int* a) {
scanf("%d", a); // a является адресом, поэтому передаем без &
}
int main() {
int n;
input(&n);
int x=10,y=5;
move(&x,&y);
printf("%d %d %d\n",n,x,y);
}
<<
7
```
Имя массива уже является адресом, поэтому при передаче массива в функцию по умолчанию он передается на изменение. Чтобы показать, что массив не будет меняться, у параметра можно указать спецификатор ``const``. Размер массива нужно передавать отдельным параметром.
```run-c
#include <stdio.h>
// найти индекс минимального элемента
int imin(const int arr[], int n) {
int im=0;
for(int i=1; i<n; ++i)
if(arr[i]<arr[im]) im=i;
return im;
}
// сортировка
void sort(int arr[], int n) {
for(int i=0;i<n-1;++i) {
int m=imin(arr+i, n-i)+i; // находим индекс минимального элемента в неупорядоченной части
int t=arr[m]; // меняем i-й и m-й элементы
arr[m]=arr[i];
arr[i]=t;
}
}
int main() {
int arr[10]={1,5,0,-4,6, 7,12,5,10,4};
sort(arr,10);
for(int i=0;i<10;++i)
printf("%d%c",arr[i],i==9?'\n':' ');
}
```
Хотя у параметра ``arr`` указывается тип ``int []``, компилятор интерпретирует это как ``int* arr`` (то есть
параметр arr можно изменять, в отличие от имени массива), но рекомендуется писать ``int arr[]``, чтобы показать, что ``arr`` -- это массив, а не указатель на одиночную переменную.
Структура в функцию передается по значению, то есть копируется, даже если вы не планируете изменять её. На копирование значения тратится время, поэтому объемные структуры (больше 16 байт) рекомендуется передавать по указателю со спецификатором ``const``. Для доступа к полям структуры, переданной по указателю, используется операция ``->``: `"указатель_на_структуру" tt"->" "имя_поля"`
```c
typedef struct { // дата и время
char day; // день 1-31
char month; // месяц 1-12
int year; // год
int time; // время суток в секундах
} datetime;
void setdmy(datetime* dt, int jdn) { // установить день, месяц год по юлианскому дню
int a=jdn+32044;
int b=(4*a+3)/146097;
int c=a-(146097*b)/4;
int d=(4*c+3)/1461;
int e=c-(1461*d)/4;
imt m=(5*e+2)/153;
dt->day=e-(153*m+2)/5+1;
dt->month=m+3-12*(m/10);
dt->year=100*b+d-4800+m/10;
}
int getjdn(const datetime* dt) { // получить юлианский день по дате
int a=(14-dt->month)/12;
int y=dt->year+4800-a;
int m=dt->month+12*a-3;
return dt->day+(153*m+2)/5+365*y+y/4-y/100+y/400-32045;
}
void addday(datetime* dt, int d) { // перейти на указанное число дней вперед или назад
setdmy(dt, getjdn(dt)+d);
}
```
Указатели на функцию часто используются как параметры функции, если отличаются не данные, которые нужно обработать, а одно из действий, которое нужно выполнить в функции.
```run-c
#include <stdio.h>
#include <math.h>
double plus(double a, double b) {
return a+b;
}
double reduce(const double a[], int n, double (*fun)(double, double)) {
// универсальная функция, которая обрабатывает весь массив, получая одно значение
double s=a[0];
for(int i=1; i<n; ++i)
s=fun(s,a[i]);
return s;
}
int main() {
double arr[10]={1.2, 5,0,-4,6, 7,12,5,10,4.1};
printf("Сумма %lf\n",reduce(arr,10,plus));
printf("Максимум %lf\n",reduce(arr,10,fmax));
}
```
В С++ для передачи переменных на изменение в функции можно использовать более простой механизм -- ссылки. В заголовке функции у параметра вместо ``*`` пишется ``&``, например, ``int& x``. При вызове функции перед аргументом ничего не пишется, также в теле функции не нужно писать операции разыменования у такого параметра или ``->`` при обращению к полям структуры, но изменения параметра приводит к изменению аргумента.
```run-cpp
#include <stdio.h>
void swap(int& x, int& y) { // обмен значений параметров
int t=x;
x=y;
y=t;
}
int main() {
int x=10,y=5;
printf("%d %d\n",x,y);
swap(x,y);
printf("%d %d\n",x,y);
}
```
Ссылки удобнее указателей, но немного уменьшается наглядность кода -- чтобы увидеть, что функция меняет какой-либо аргумент, нужно изучить заголовок этой функции.
Значения типа ``vector`` и ``string`` рекомендуется передавать по ссылке (если не меняется -- указать спецификатор ``const``).