Цель работы
Изучить способы объявления и использования массивов в языке С++; изучить понятие «указатель» и операции над указателями, а также принципы использования указателей при работе с массивами.
Краткие теоретические положения
Массивы. Массив по существу является совокупностью однотипных переменных (элементов массива), объединенных под одним именем и различающихся своими индексами. Массив объявляется подобно простой переменной, но после имени массива указывается число его элементов в квадратных скобках:
int myArray[8];
Массив, как и переменную, можно инициализировать при объявлении. Значения для последовательных элементов массива отделяются друг от друга запятыми и заключаются в фигурные скобки:
int iArray[8] = {7, 4, 3, 5, 0, 1, 2, 6);
Обращение к отдельным элементам массива производится путем указания индекса элемента в квадратных скобках, например:
myArray[3] = 11;
myArray[i] = iArray[7-i];
Индекс должен быть целым выражением, значение которого не выходит за пределы допустимого диапазона. Поскольку индексация массивов начинается в С всегда с нуля (т. е. первый элемент имеет индекс 0), то, если массив состоит из N элементов, индекс может принимать значения от 0 до N-1. В языке С не предусмотрена автоматическая проверка допустимости значений индекса времени выполнения, поэтому при индексации массивов нужно быть внимательным. Выход индекса за границы массива может приводить к совершенно непредсказуемым результатам. При работе с массивами обычно используют оператор цикла for.
Пример программы. Ввод с клавиатуры одномерного массива и вычисление среднего арифметического (справа изображена схема алгоритма):
#include <iostream>
#include <conio.h>
using namespace std;
int main()
{int i, a[6],s=0; float sred;
for (i=0;i<6;i++)
{cout <<"Vvedite element N"<<i<< ":";
cin >> a[i];
s+=a[i];
}
sred=(float)s/6;
cout << "Srednee znachenie v massive: " << sred << "\n";
getch();
}
Указатели. Указатель — это переменная, которая содержит адрес другого объекта. Объявление указателя выглядит так:
тип_указываемого_объекта *имя_указателя [= значение];
Операция & - адрес. Применение этой операции к имени переменной дает в результате ее адрес в памяти. Например, объявим переменную:
int x; // Целое х.
Опишем указатель:
int *ptr1; // Указатель на целое.
После такого описания переменная ptr1 может принимать значение указателя на величину целого типа. Этой переменной можно присвоить значение так:
ptr1=&x;
Чтобы получить доступ к объекту, на который указатель ссылается. последний разыменовывают (разадресовывают), применяя операцию-звездочку. Единицей изменения значения указателя является размер соответствующего ему типа.
Указатели используются при обработке строк, а также для передачи функциям параметров, значения которых могут ими изменяться (передача по ссылке). Но главное «достоинство» указателей в том, что они позволяют создавать и обрабатывать динамические структуры данных. В языке С можно выделить память под некоторый объект не только с помощью оператора объявления, но и динамически, во время исполнения программы. Для работы с динамической памятью можно использовать операции new и delete. Выражение с операцией new имеет обычно вид:
указатель_на_тип = new имя_типа <(инициализатор)>
Например:
int *ip = new int;
При этом создается два объекта: динамический безымянный объект и автоматический или статический указатель с именем ip, значением которого является адрес динамического объекта. Можно создать и другой указатель на тот же динамический объект:
int *other_p=ip;
С другой стороны можно потерять доступ к нашему динамическому объекту, просто присвоив указателю ip другое значение:
int i; ip = &i;
В результате динамический объект будет существовать по-прежнему, но обратиться к нему будет уже невозможно. Другие примеры:
int *ip1= new int(1); // дин. объект с инициализацией
int *array = new int[10]; // динамич. массив
double **d = new double*[j]; // дин. массив указателей
//на double. Число элементов равно j.
В случае успешного завершения операция new возвращает указатель со значением отличным от нуля. Иначе – NULL, нулевой указатель.
Операция delete освобождает участок памяти, выделенный раннее операцией new.
Указатели и массивы. Между указателями и массивами в С существует тесная связь. Имя массива без индекса эквивалентно указателю на его первый элемент. Поэтому можно написать:
int iArray[4];
int *piArr;
piArr=iArray; //piArr указывает на начальный элемент iArray.
Последнее эквивалентно
piArr = &iArray[0];
И наоборот, указатель можно использовать подобно имени массива, г. е. индексировать его. Например, piArr [3] представляет четвертый элемент массива iArray[].
Таким образом, в выражениях с указателями и массивами можно обращаться одинаково. Следует только помнить, что объявление массива выделяет память под соответствующее число элементов, а объявление указателя никакой памяти не выделяет, вернее, выделяет память для хранения значения указателя — некоторого адреса. Компилятор по-разному рассматривает указатели и массивы, хотя внешне они могут выглядеть очень похоже.
Пример программы:
#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
main()
{ int i, *ip, N, S=0;
cin >> N;
ip= new int [N];
if (ip!= NULL)
{ cout << "Массив создан успешно. \n";
for (i=0;i<N;i++)
{ cout << "Введите " << i <<"-й элемент: ";
cin >> *(ip+i);
S+=ip[i];
}
cout << "Сумма элементов: "<< S << "\n";
delete ip;
}
else cout << "Ошибка выделения динамической памяти! \n";
getch();
}
Задание на работу
1. Разработать приложения с использованием массивов по своему варианту.