- •Аннотация
- •Предисловие
- •Г л а в а 1. Введение в указатели
- •§1. Понятие указателя. Операции разыменования и разадресации
- •§2. Инициализация и присваивание указателей
- •§3. Передача параметров функций с помощью указателей.
- •§4. Распределение динамической памяти.
- •4.1. Операция new
- •4.2. Операция delete
- •Упражнения, тесты.
- •Указатели и массивы
- •§1. Связь указателей и массивов
- •1.1. Указатели и одномерные массивы
- •1.2. Указатели и матрицы
- •Int MyFun (int *X, int n)
- •§3. Операции над указателями при работе с массивами.
- •3.1. Арифметические операции
- •3.2. Операции сравнения.
- •§4. Использование операций над указателями при работе с одномерными массивами
- •4.1. Использование индексов
- •4.2. Указатель в качестве параметра цикла
- •4.3. Использование указателя и индекса
- •§5. Строки.
- •5.1. Общая характеристика строк.
- •5.2. Примеры алгоритмов работы со строками.
- •5.3. Анализ строковых функций.
- •§6. Использование операций над указателями при работе со статической матрицей.
- •Упражнения, тесты.
- •Массивы указателей
- •§1. Статический массив указателей
- •§2. Частично динамическая матрица.
- •Int arr_of_size[n];
- •§3. Статический массив строк
- •§4. Динамический массив указателей
- •4.1. Указатель на указатель
- •4.2. Динамические “матрицы”.
- •Int *arr_of_size;
- •4.3. Передача матрицы в функцию
- •Int a[10]; FunArr1(a, 10,…);
- •Упражнения, тесты.
- •Задачи второго среднего уровня.
- •Структуры и другие типы, определяемые пользователем
- •§1. Структуры
- •Объявление структуры
- •1.2. Работа со структурой.
- •1.3. Вложенные структуры и статические массивы в структурах
- •1.4. Статический массив структур
- •§2. Cтруктуры и указатели
- •2.1. Указатели в структуре.
- •2.2. Указатели на структуру
- •2.3. Динамический массив структур
- •2.4. Ссылка на структуру.
- •2.5. Указатели и вложенные структуры
- •§3. Cтруктуры и функции
- •3.1. Передача полей структуры в функцию.
- •Void MyFun1 (int X, float &y, int *u1, float *u2, char *s);
- •3.2. Передача всей структуры в функцию
- •Void Fun1 (tst s,…);
- •Void Fun2 (tst & s,…);
- •Void Fun3 (tst* s,…);
- •§4. Cтруктуры и классы.
- •§5. Объединения.
- •Представление вещественных чисел в памяти компьютера.
- •§6. Поля битов (битовые поля)
- •Ввод в ы в о д
- •Symbol Code16 Code10 Code2
- •§7. Перечисления
- •Какие из строк (//1 – //9) правильные?
Упражнения, тесты.
1. Пусть int t=10; int *p=&t; Какие из следующих операторов допустимы и что они означают (что будет выведено, какое значение примет переменная): 1) cout<< p; 2) p=1000; 3) *p=1000; 4) t*=*p; 5) cout<<(*p); 6)cout <<(*p*=2)?
2. Дан код:
void fun1 (int *x, int &y) { (*x)++; y--;} //1
void main() { int a=5, b=2; fun1 (&a, b); //2
cout<< a<< “ “<< b; getch() ; }
Что будет выведено?
Варианты ответов: 1) 6 1; 2) 5 1; 3) 6 2; 4) 5 2; 5) Ошибка в //1;
6) Ошибка в //2; 7) Ошибки в //1 и //2.
3.. Дан код:
void fun4 (int x, int *y) { * y=x*10; } //1
void main() { int a=5, *b=new int (2); //2
fun4 (????????); //3
cout<< a<< “ “<< (*b); getch() ; } //4
Что записать в скобках в строке //3, чтобы вывести 5 50?
Варианты ответов: 1) fun4(a,b); 2) fun4(a, &b); 3) fun4(&a, &b);
4)fun4(a, *b); 5) ошибки (указать номера строк).
4. Дан код:
void fun5(int &x, int *y)
{ ????????????? ; } //1
void main()
{ int a=5, *b=new int; //2
fun5 (a,b); //3
cout<<endl<<a<<" "<<(*b)<<endl; //4
getch(); }
Что записать в тексте функции в строке //1, чтобы вывести 5 15?
Варианты ответов: 1) y=x+10; 2) *y=*x+10; 3) *y=x+10; 4)y=*x+10;
ошибка в //2 6) ошибка в //3 ; 6) ошибка в //4 .
5. Дан код:
int *p1= new int = 11; int *p2; *p2= new int =11; int *p3= new int[11];
int *p4= new int (11); int *p5= new (int) 11; int *p6= new int :11;
Для каких указателей (p1 — p6) правильно резервируется память для одной целочисленной переменной и выполняется её инициализация?
Г л а в а 2
Указатели и массивы
В этой главе изучается связь указателей с одномерными и двумерными массивами, рассматриваются арифметические операции и операции сравнения для указателей на массивы и основанный на них другой метод программирования циклов при работе с одномерными массивами, матрицами и строками. Этот метод явно использует указатели, а не индексы, как это было в первом семестре ([1]). Здесь же рассматривается порядок создания и работы с динамическим одномерным массивом.
§1. Связь указателей и массивов
1.1. Указатели и одномерные массивы
Рассматриваемые выше вопросы усложняются ещё и тем, что для массивов они решаются по-другому. Пусть мы объявили статический массив: const m=10; int a[m]; Этим самым мы не только выделили память для размещения m целых чисел. Без какого-либо дополнительного объявления, без использования символа “*” мы объявили и переменную-указатель с именем a. В этой переменной находится адрес начала массива, т. е. номер первого байта элемента a[0]. Этот адрес можно в программе обозначить ещё и как &a[0].
Идентификатор массива определяется не просто как указатель, а как константный указатель на первый элемент массива. Это означает, что нельзя изменить адрес начала массива, то есть нельзя, например, переменной a присвоить значение другого адреса. Если int *q, то запись a=q; недопустима, а обратное присваивание q=a; или q=&a[0]; разрешено. После этого элементы массива можно обозначать не только a[i], но и q[i], где i =0, 1, 2, …, m-1. Если q=&a[5], то q[0] — это a[5], q[1] — это a[6], и т. д., q[4] — a[9].
При использовании одномерного массива в качестве параметра функции заголовок функции можно записать по-разному. Например, функцию сортировки можно объявить двумя способами:
a) void MySort(int x[], int size); или
b) void MySort(int *x, int size);
В любом случае в качестве параметра передаётся адрес начала массива. Более того, в прототипе можем записать int x[], а в заголовке при определении этой же функции — int * x или наоборот. В тексте функции для доступа к элементу массива можно использовать обычную индексированную переменную x[i]. Но вызов такой функции выполняется одинаково и не зависит от вариантов (a) или b)). В вызывающей функции объявляем статический массив обычным образом, например, const m=10; int a[m]; При вызове функции в качестве фактического параметра надо записать адрес начала массива, если обрабатываем его с самого начала. Поэтому в скобках в таком случае записываем только имя массива a или адрес его первого элемента &a[0], что одно и тоже. Будет ошибка, если при вызове функции в качестве фактического параметра запишем, например, a[i] (так можно писать внутри функции), или a[m] (так объявляем массив), или a[] (так можно определить формальный, а не фактический параметр). Таким образом, функцию можно вызвать одним из следующих способов:
a) MySort (a, m); или MySort (&a[0], m); для сортировки всех m элементов массива;
b) MySort (a, m/2); или MySort (&a[0], m/2); для сортировки m/2 первых элементов массива;
c) Пусть надо рассортировать массив не с самого начала, а, например, с его середины и до конца. Тогда в качестве фактического параметра при вызове такой функции указываем адрес элемента a[m/2], а количество обрабатываемых элементов уменьшаем в два раза: MySort (&a[m/2], m%2 ? m/2+1 : m/2).
Заметим, что в вариантах b) и c) требуется уточнение и пояснение в случае, если m — нечётное. Если, например, m=15, то в варианте b) рассортируем первые 7 элементов массива, то есть меньше половины. В варианте c), начав с a[7], мы должны рассортировать 8= n/2+1 элементов, то есть больше половины. При n чётном (n%2=0, что соответствует false) рассортируем n/2 элементов.
В [1] смотри объяснение, как передаётся одномерный массив в качестве параметра функции.