Массивы и указатели
Определение массива
type имя_массива [ константное_выражение] инициализатор;
где type – тип элементов массива; имя_массива – идентификатор массива; инициализатор – не обязательное инициализирующее выражение; константное_выражение – выражение, значение которого вычисляется во время компиляции, а не во время выполнения программы. Это значит, что во время выполнения программы нельзя увеличивать размерность массива. Поэтому такие массивы называются статическими.
int f [3];
Инициализировать элементы массива можно следующим образом:
int f[] = {2, 5, ‘S’};
или так
int f[] {2, 5, ‘S’};
/*Вместо символа S компилятор подставит соответствующее ему по таблице ASCII число. Размер массива равен трем, задаётся неявно с помощью инициализатора.*/
char a[5] = {2, 5, ‘S’}; /* Размер массива равен 5 задаётся явно. Первые три элемента массива инициализируются соответствующими значениями. */
char a[2] = {2, 5, ‘S’};// Ошибка инициализации
a[10]
Для массивов типа char принят ещё один способ инициализации:
char pc[] = “Привет всем”;/*Размер массива равен 12, задаётся неявно и определяется количеством символов, заключенных в кавычки, плюс невидимый, так называемый нулевой символ ‘\0’. Полным аналогом такого способа инициализации является строка char pc[] = {‘П’, ‘р’, ’и’, ’в’, ’е’, ’т’,’ ’,’в’,’с’,’е’,’м’,’\0’};*/
Также как переменная, массив может быть определен в программе один раз, но много раз может быть описан следующим образом:
extern type имя_массива[];
где type и имя_массива должны совпадать с типом и именем массива определенного где-то в программе. Type можно опустить, в этом случае по умолчанию будет предполагаться, что type имеет тип int. Пример:
extern f[]; //Описание массива типа int, определенного где-то в программе.
extern char pc[];/*Описание массива типа char, определенного где-то в программе.*/
Если массив был описан, но не определен, то на этапе компоновки будет выдано сообщение об ошибке.
Над именем массива определена операция sizeof(имя_массива). Результатом этой операции является количество байт, выделенных под массив. Используя эту операцию можно определить, сколько есть элементов в массиве, например:
double k[5];
cout<<”\n Количество элементов в массиве k = “;
cout<<sizeof(k)/sizeof(double); //
Результат работы программы:
Количество элементов в массиве k = 5
Доступ к конкретному элементу массива при определении массива в виде type имя_массива[константное_выражение] можно выполнить с помощью операции имя_массива[индекс], причём программа должна быть написана так, чтобы изменение индекса лежало в пределах интервала от 0 до константного_выражения – 1 включительно. При выходе индекса за пределы интервала программа начинает обращаться к памяти, которая не была выделена под массив и, следовательно, результаты работы такой программы непредсказуемы. Ни компилятор, ни компоновщик не проверяют диапазон изменения индекса, программист сам должен обеспечивать выполнение правила обращения к элементам массива.
Имя массива – это константный указатель, значение которого равно адресу первого элемента массива. Единственное отличие, которое есть, например, между именем массива ai и константным указателем pi, определенным ниже как
int ai[5];
int * pi = &ai[0];/* или int * const pi = ai; т.е. &ai[0] = = ai заключается в результате выполнения операции sizeof(), так при выполнении операции sizeof(ai) результат будет равен 10, а sizeof(pi) результат будет равен 4. Поскольку ai это имя массива, которое является константным указателем, а pi – константный указатель, настроенный на первый элемент массива. */
Во всем остальном они подобны. Это означает, что к указателям можно применять операцию [ ], а к именам массивов все правила адресной арифметики, связанной с указателями. Более того, запись имя_массива[индекс] является выражением с двумя операндами. Первый из них, т.е. имя_массива – это константный указатель – адрес начала массива в основной памяти; индекс - это выражение целого типа, определяющее смещение от начала массива. Используя операцию обращения по адресу *, действие бинарной операции [индекс] можно объяснить так: *(имя_массива + индекс). Поскольку операция сложения коммутативна, то можно записать и так *(индекс+ имя_массива), а, следовательно, операцию [], можно представить в виде индекс[имя_массива]. Например, обращение к элементам массива ai через имя массива или указатель pi, которые были определены выше, можно записать
ai[0] == pi[0] == *ai == *pi == 0[ai] == 0[pi],
ai[1] == pi[1] == *(ai+1) == *(pi+1)== 1[ai] == 1[pi],
ai[4] == pi[4] == *(ai+4) == *(pi+4)== 4[ai] == 4[pi].
Но ошибкой будет запись *(ai++), или *(pi++), или *(pi = pi+4), или *(ai = ai+4), так как ai и pi - константные указатели. Необходимо также помнить, что при прибавлении целого числа (индекса) к указателю на самом деле прибавляется число равное индекс*sizeof(type), где type - тип объекта, к которому отнесен указатель.
Использовать операцию [] c указателями очень удобно. Она коротка с точки зрения записи, интуитивно понятна, не изменяет значение указателя и может использоваться и с неконстантными указателями. Например, напишем функцию, которая в обратном порядке выводит на экран содержимое строки.
//Программа 5.4
#include "stdafx.h"
#include <iostream>
void fstr(char* pst){
int strlen = 0;
for(; pst[strlen] != '\0'; strlen++); /*Определяем длину строки. Телом цикла является пустой оператор. */
for(int i = strlen-1; i >= 0; i--) std::cout<< pst[i]; /*Выводим строку посимвольно в обратном порядке на экран, используя указатель pst и операцию []. */
}
void main(){
char p [] = "Example work of operation []";
fstr(p);/*При вызове функции формальному параметру pst присваивается значение фактического параметра p. Таким образом, указатель pst настраивается на первый элемент массива р.*/
getchar();
}
Дата добавления: 2020-12-11; просмотров: 413;