Загрузка [MathJax]/jax/output/HTML-CSS/fonts/TeX/fontdata.js
 

printУказатели и динамическая память

printУказатели

Указатель – это переменная, которая хранит адрес другой переменной. Если переменная имеет тип int, то указатель имеет тип int* (т.е. добавляется *).

Для получения значения переменной, на которую указывает указатель, используется унарная операция * (разыменования), а для получения адреса переменной – унарная операция &.

#include <stdio.h>
int main() {
  int x=10;
  int* ptr_x=&x; // сохраняем адрес x
  printf("%p\n", ptr_x); // печать адреса
  printf("%d\n", *ptr_x); // получение значения по адресу
  ++x; // x=11
  printf("%d\n", *ptr_x); // получение значения по адресу
}
Ввод:

Выполнить
Вывод:

Чтобы показать, что указатель никуда не указывает, ему можно присвоить значение 0 (nullptr в С++/C23). Перед разыменованием указателя можно проверить, указывает ли он на что-то. Это не гарантирует, что адрес правильный, так как вы могли не инициализировать указатель (мусор) или там окажется адрес уже не существующей переменной, возможно ошибки выполнения не будет, но это считается undefined behavoir (UB).

#include <stdio.h>
int main() {
  int* ptr=0; // UB без =0
  { int x=10;
//    ptr=&x; // UB при обращении к *ptr вне блока
  }
  if(ptr) // OK, не нулевой
    printf("%d\n", *ptr);
  else
    printf("nullptr\n");
//  printf("%d\n", *ptr); // ошибка выполнения при =0 
}
Ввод:

Выполнить
Вывод:

Имя массива является константным указателем на первый элемент массива (т.е. сам указатель изменять нельзя, но можно изменять значение, на которое он указывает). Можно определить вспомогательный указатель и перемещать его по массиву (при этом нужно убедиться, что указатель не вышел за левую или правую границу массива).

#include <stdio.h>
int main() {
  int arr[10]={0}; // все нули
  // int *const arr=&arr[0];
  *arr=5;
  int *ptr=arr; // ptr=&arr[0];
  ++ptr; // ptr=&arr[1];
  *ptr=6;
  ptr+=4; // ptr=&arr[5];
  *ptr=7;
// печать массива
  for(int i=0;i<10;++i)
    printf("%d ",arr[i]);
  printf("\n");
// тоже самое через указатель
  for(ptr=arr;ptr!=arr+10;++ptr)
    printf("%d ", *ptr);
  printf("\n");
}
Ввод:

Выполнить
Вывод:

Адреса имеют не только переменные, но и функции, скомпилированный код которых хранится в памяти компьютера. Можно определить указатель, который хранит адрес функции:
double (*f)(double);
Скобки вокруг (*f) обязательны, так как строка
double *f(double);
является заголовком функции, которая возвращает результат типа double*

Имя функции (как и имя массива) является константным указателем на функцию. Например,

f=sin; // f указывает на функцию sin
double x=f(0.5); // вызываем sin(0.5);
f=trunc;
x=f(1.5); // вызываем trunc(0.5);

Массив указателей на функцию:

double (*math[4])(double)={sin,trunc,fabs,sqrt};
x=math[2](-1.2); // fabs(-1.2);
loading