10.15 Указатели
Адреса в памяти
Бывает по-разному, но обычно у запущенной программы в ОС:
- ↓ стек
- недоступная память
- ↑ куча
- статическая память
Почему так? Потому что!!! (+потому что виртуальная память, а так удобнее)
Указатели в Си
C: статическая память выделяется при старте программы ну, почти, стек — изменяется автоматически, куча — по запросу от программы.
Взятие адреса и "%p"
Завести три переменные, вывести их адреса. В каком порядке объявленные переменные располагаются в памяти? - TODO: заводить три локальные и три глобальные переменные, вывести вначале адреса локальных, потом - адреса глобальных
- Правильный ответ: неизвестно!
В чём различие локальных и глобальных?
Взятие значения по адресу. Адресная арифметика. Тип «указатель» указатель переменной + 1 == адрес переменной + sizeof(переменной)
BTW, sizeof() — не функция, это оператор; sizeof(массив)
Объявить три переменных — две целых и float, равные 1,2 и 3, и указатель на целое pointer. Положить в pointer адрес первой переменной, вывести содержимое по адресу
- Увеличить указатель на 1, вывести содержимое по адресу
- Увеличить указатель на 1, вывести содержимое по адресу
Объяснить явление
Зачем вся эта возня?
Имя массива — это его адрес (можно не писать &)
Соседний элемент массива — вполне штатная операция, собственно индексирование! arr[i] ≡ arr+i
Написать функции inputArray(int n, int *array) и outputArray(int n, int *array), ввести и вывести массив из n элементов (не пользуясь []) Попробовать вместо элементов 0…9 вывести элементы -2…11. Вспомнить про -fsanitize=address
Локальные динамические массивы
Небольшие (на классических архитектурах — в пределах килобайта) массивы можно заводить на стеке. Смысл — в том, что их длина может быть произвольной.
VLA (variable length array) - массив, размер которого вычисляется и задаётся во время выполнения программы (runtime), а не на этапе компиляции. Например, массив int arr[n], определяемый внутри функции, в которую передается параметр n.
Ввести n, завести массив arr на n элементов, ввести и вывести с помощью inputArray/…
Посмотреть также sizeof(arr)
Можно ли завести локальный массив в функции и вернуть его адрес?
Размерность массива в сигнатуре функции
В текущем стандарте можно (и нужно!) писать inputArray(int n, int array[n]), но именно для формального параметра разницы никакой, это всё равно указатель int *, а не VLA.
Т. е. делается это
- Для прагматики
- Для определения размерностей многомерного массива
Написать функцию outputMatrix(int w, int h, int array[h][w]), которая считает массив прямоугольным w×h и выводит его соответственно по строкам; попробовать один и тот же массив на 12×1, 6×2, 4x3 и т. д.
Д/З
1. Ввести натуральное число n, целые числа $$a_1, ..., a_{3*n}$$. Написать функцию accept(), которой передаётся длина массива и указатель на массив, а она выясняет, верно ли, что для всех $$a_{2n+1}, ..., a_{3n}$$ имеются равные среди $$a_1, ..., a_{2n}$$, и возвращает соответствующее значение. Вывести "YES", если да, и "NO" в противном случае.
3 1 2 3 1 2 3 1 2 3
→
YES
3 1 2 3 4 5 6 7 3 1
→
NO
2. Ввести натуральное число n, целые числа $$a_1, ..., a_{n}$$. Написать функцию reorder(), которой передаётся длина массива и указатель на массив, а она располагает в нём вначале отрицательные члены, а затем - неотрицательные. При этом порядок как отрицательных, так и неотрицательных чисел сохраняется прежним. Вывести преобразованную последовательность.
10 1 -1 -2 -1 2 0 -1 32 -3 3
→
-1 -2 -1 -1 -3 1 2 0 32 3
3. Ввести
- натуральное число n;
- элементы действительной матрицы размера n × (n + 1), ввод по строкам;
действительные числа $$a_1, ..., a_{n+1}, b_1, ..., b_{n+1}$$;
- натуральные числа p, q (p ≤ n, q ≤ n+1).
Образовать матрицу размера (n + 1) × (n + 2) вставкой после строки с номером р исходной матрицы новой строки с элементами $$a_1, ..., a_{n+1}$$ и последующей вставкой после столбца с номером q нового столбца с элементами $$b_1, ..., b_{n+1}$$ (нулевые значения p или q — вставка в начало). Вывести полученную матрицу по строкам, каждую строку — на отдельной строке экрана.
3 1 2 3 4 5 6 7 8 9 0 1 2 10 11 12 13 21 22 23 24 1 2
- Обратите внимание на то, что в задаче нумерация начинается с 1
1.0 2.0 21.0 3.0 4.0 10.0 11.0 22.0 12.0 13.0 5.0 6.0 23.0 7.0 8.0 9.0 0.0 24.0 1.0 2.0
- Красиво форматировать можно, но не обязательно ☺: в каждой строке проверяется только правильность последовательности вещественных чисел с определённой точностью
4. Ввести натуральное n и заполнить целочисленную квадратную матрицу n×n цифрами — разрядом единиц в последовательности 1, 2, ..., n², расположенными в ней по спирали: снаружи внутрь, по часовой стрелке, начиная с левого верхнего элемента с индексами [0; 0].
7
→
1 2 3 4 5 6 7 4 5 6 7 8 9 8 3 0 1 2 3 0 9 2 9 8 9 4 1 0 1 8 7 6 5 2 1 0 7 6 5 4 3 2 9 8 7 6 5 4 3
К этой задаче будет спойлер по алгоритму в виде схемы
