учебники, программирование, основы, введение в,
Как выучить японский язык пошаговое, megapoisk.

 

Производные типы данных языка C++. Массивы и указатели

Производные типы
Производные типы можно условно подразделить на две группы:

  • Непосредственно производные типы. Эти типы являются производными от некоторых существующих типов, реализуя типы указателей, ссылки, функции преобразования типов. В группу непосредственно производных типов входят:
    • массивы
    • указатели
    • ссылки
    • перечисления
    • указатели на члены класса.
  • Составные производные типы. В группу составных производных типов входят:
    • классы
    • структуры
    • объединения

Массивы
Объявление массивов
Массив переменных или объектов состоит из определенного числа однотипных данных, называемых элементами массива. Все элементы массива индексируются последовательно, начиная с нуля.
Размещение элементов массива в памяти выполняется последовательно.
Количество элементов в массиве определяет размер массива и является константным выражением. Для создания динамических массивов стандартная библиотека C++ предусматривает тип vector.
Имя массива определяет адрес первого элемента массива.
Имя массива в отличие от имени вектора нельзя указывать в левой части оператора присваивания.
Объявление массива может иметь следующее формальное описание:
// Объявление одномерного массива
тип имя_массива[размерность_N];
// Объявление одномерного массива с
// одновременной инициализацией
тип имя_массива[размерность_N]=
{значение0, значение1, ..., значение_N-1};
// Объявление безразмерного массива с
// одновременной инициализацией:
// размерность определяется количеством
// значений, указанных в списке инициализации
тип имя_массива[]={значение0, значение1,
..., значение_N-1};
// Объявление многомерного массива
тип имя_массива[размерность_1N]...
[размерность_MN];
// Объявление многомерного массива с
// одновременной инициализацией
тип имя_массива
[размерность_N]... [размерность_M] =
{ {значение0, значение1, ..., значение_M-1},
...
{значение0N, значение1N, ..., значение_NM-1}};
Размерность массива может:

  • указываться любым константным выражением целого типа;
  • автоматически определяться компилятором по списку значений инициализации массива (если размерность не указана явно).

Например:
int arrayOfInteger[17];     
// Массив из 17 переменных типа int
char arrayOfChar_3[3]={'L','M','N'};    
// Объявление и инициализация
// символьного массива
char arrayOfChar_0[]={"Array of char. \n"};
int arrayOfInteger_6[2][3]=    {
{1,2,3}, {11,12,13}};     
// Объявление и инициализация
// двумерного массива
Если ни размерность массива, ни список значений инициализации не указаны, то будет создан массив нулевой длины.
Объявление многомерных массивов выполняется по следующим правилам:

  • список значений инициализации можно указывать как в единых фигурных скобках, так и в общих фигурных скобках, включающих через запятую списки по каждому левому индексу в отдельных фигурных скобках;
  • при использовании общих фигурных скобок сначала следует указывать значения для неизменяемого самого левого индекса;
  • можно не указывать только самую левую размерность массива, получая ее значение из списка значений инициализации.

Инициализацию массива можно выполнить одним из следующих способов:

  • указать во время объявления массива в фигурных скобках значения инициализации (начиная с нулевого элемента и первого столбца);
  • присвоить значение элементам массива во время выполнения программы;
  • объявить массив как глобальный или статический, инициализируемый по умолчанию (для числовых значений выполняется инициализация нулями, а для указателей - значением null). Глобальный массив объявляется вне всех функций, а статический массив объявляется с модификатором static.

Если количество значений инициализации больше, чем объявленная размерность массива, то компилятор Visual C++ инициирует ошибку.
Если количество значений инициализации меньше, чем объявленная размерность массива, то оставшиеся значения автоматически инициализируются нулями.

http://localhost:3232/img/empty.gifРазмещение массива в памяти

При создании массива память под все его элементы выделяется последовательно для каждого элемента в зависимости от типа массива. Для многомерных массивов в первую очередь изменяются значения самого правого индекса.
Например, для массива char aCh[2][4] будет выделено восемь байтов памяти, в которых в следующем порядке будут размещены элементы массива:


элемент

aCh[0][0]

aCh[0][1]

aCh[0][2]

aCh[0][3]

aCh[1][0]

aCh[1][1]

aCh[1][2]

aCh[1][3]

N байта

1

2

3

4

5

6

7

8

Двухмерные массивы можно рассматривать как матрицу, в которой первый индекс определяет строку, а второй индекс - столбец. Порядок расположения элементов матрицы в памяти - по строкам.
При размещении трехмерного массива char aCh[3][2][5] память под элементы этого массива будет выделяться последовательно в соответствии со следующими значениями индексов:
Общий объем выделяемой под массив памяти определяется как произведение всех размерностей массива (общее число элементов), умноженное на длину типа данных массива.
Элементы массива
Доступ к элементам массива может выполняться:

  • по указателю на массив и индексу элемента, задаваемого в квадратных скобках: первый элемент массива имеет индекс 0;
  • по указателю на элемент массива.

Для получения адреса элемента массива применяется оператор &.
Имя массива является адресом массива и эквивалентно следующему выражению: &имя_массива[0].
Для определения размерности массива в байтах можно использовать функцию sizeof(имя_массива).
Например:
arrayOfInteger[0]=1;       
// Присваивание значения
// первому элементу массива
iInt1=arrayOfInteger[1]=13;       
// Групповое присваивание
iInt2=&arrayOfInteger[4];       
// Получение адреса пятого
// элемента массива
Символьные массивы и строки
Синтаксис языка не имеет простого строкового типа (стандартная библиотека содержит тип string, но переменные данного типа не являются массивами символов). Поэтому для работы со строками удобно использовать массивы символов. Объявить массив символов - строку можно двумя способами:

  • указать посимвольно каждый элемент массива, включая символ конца строки;
  • указать в двойных кавычках при инициализации массива значение строки (символ конца строки будет добавлен автоматически).

Символом конца строки служит null-символ \0. При подсчете числа символов в строке учитывается общее число символов плюс символ конца строки.
Например:
char arrayOfChar[6];
arrayOfChar[0]='A'; 
// Доступ через указатель
// на массив и индекс
char * ph = arrayOfChar;  
// Создание указателя на элемент массива
ph++;                       
// Переход к следующему элементу массива
Префиксный оператор * называется оператором разыменования. Если ph указывает на элемент массива, то *ph является значением этого элемента.
Любое выражение, имеющее тип массива, может быть преобразовано к указателю того же типа: результатом будет указатель на первый элемент массива.
Например:
char cStr[_MAX_PATH];    
// Массив типа char
char *pStr = cStr;      
// Указатель на массив:
// эквивалентно выражению &cStr[0]

http://localhost:3232/img/empty.gifУказатели

Указатели на переменные
Указатель на переменную содержит адрес памяти расположения этой переменной.
Объявление указателя имеет следующее формальное описание:
тип_переменной *имя_переменной_адреса;
Инициализация указателя выполняется следующим образом:
тип_переменной имя_переменной_содержания;
имя_переменной_адреса =
&имя_переменной_содержания;
Объявление указателя может быть выполнено с одновременной инициализацией:
тип_переменной *имя_переменной_адреса =
&имя_переменной_содержания;
Доступ к значению переменной по указателю имеет следующее формальное описание:
имя_переменной_содержания1=*имя_переменной_адреса;
При работе с указателями действуют следующие правила:

  • при объявлении переменной-указателя перед именем переменной указывается операция *;
  • если одним оператором объявляется несколько переменных-указателей, то перед каждой такой переменной следует указывать операцию *;
  • после объявления указателя его следует инициализировать адресом значения того же типа, что и тип указателя;
  • для получения адреса переменной перед ее именем указывается операция взятия адреса &;
  • для получения значения переменной по указателю на нее перед указателем ставится операция разыменования * (называемая иногда операцией взятия значения);
  • указатель строки содержит адрес первого символа строки;
  • при увеличении указателя на единицу значение, содержащееся в переменной-указателе, увеличивается на число байт, которое отведено под переменную данного типа.

Операцию разыменования & нельзя использовать:

  • для регистровых переменных (register r1; pReg=&r1;);
  • с константами (pAdr1=&444;);
  • с арифметическими выражениями (int i=1234; pAdr1=&(i+3);).

Например:
int iVar;
int* pInt;     // Указатель
pInt=&iVar;    // Эквивалентно оператору
// int *pInt=&iVar;
*pInt=20;      // Эквивалентно оператору
// iVar=20;
char* pStr="The string";
iVar=strlen(pStr);       
// Определение длины строки
Указателю может быть присвоено значение другого указателя: в этом случае следует использовать операцию *. Компилятор Visual C++ отслеживает некорректные присваивания - указателю значения или наоборот, и выдает предупреждение о различных уровнях адресации.
На следующей схеме иллюстрируется соотношение указателя и значения.

Переменные

Указатели

Объявление и инициализация

char A

char B

char*pA

char*pB

Адреса ячеек памяти

2000

2001

3000

3020

Операции:

Содержание ячеек:

A='w';

w

pA=&A; //адрес переменной А

2000

B=*pA; //значение переменной А

w

*pA='я'; //изменение значения

я

pB=pA; //адрес переменной А

2000

pB=&A; //адрес переменной А

2000

Операции инкремента ++ и декремента -- указателя можно выполнять как после операции присвоения (*pV++=22;), так и до нее (*++pV=22;). В последнем случае сначала будет увеличено значение указателя, а затем выполнен оператор присваивания.
Выполнять вычитание можно только над указателями одного типа. Результатом вычитания указателей является целое число, указывающее разность адресов памяти.
Над указателями одного типа можно выполнять операцию сравнения, возвращающую логическое значение.
Так же как и при работе с массивами, компилятор Visual C++ не выполняет для указателей проверку на предельные значения.
Константные указатели
Значение указателя на константу можно изменять, а значение константного указателя является константой и не подлежит изменению.
Например:
char str1[]="123";
const char* pstr1= str1; 
// pstr1 можно изменять,
// а *pstr1 - нельзя.
Задание ключевого слова const перед объявлением указателя создает этот указатель как указатель на константу (при этом само значение, доступное не через данный указатель, остается изменяемым).
Для того чтобы создать константный указатель, вместо оператора * используется *const.
Например:
const char *const pstr1= str1;
Указатели на массивы
И указатель, и массив содержат адрес. Поэтому указателю может быть присвоен адрес первого элемента массива или имя массива. Но адресу массива нельзя присвоить значение указателя.
Например:
float fArray[3];  // Массив
float* pArray;
pArray=fArray;   // Эквивалентно оператору
// pArray=&fArray[0];
pArray++;        // Указывает на второй
// элемент массива
float* pArray2;
pArray2=&fArray[1]; // Указывает на второй
//элемент массива

http://localhost:3232/img/empty.gifУказатели на указатели

Объявление указателя на указатель имеет следующее формальное описание:

тип **имя_указателя_на_указатель;

При объявлении указателя на указатели уровнем вложенности указателей служит число звездочек перед именем переменной.
Для получения значения по указателю на указатели перед именем указателя надо записать количество звездочек, равное уровню вложенности указателя.
Например:

int iV, jV;
int* pV=&iV;     // pV - это адрес, 
                     //а *pV - значение
int** ppV=&pV;
int*** pppV=&ppV;
iV=77;    // Эквивалентно **ppV=77;
jV=*pV;   // Эквивалентно jV=**ppV; 
          // или jV=***pppV;

Ссылки

Ссылка вводит для доступа к переменной второе имя и является константным указателем на объект. Значение переменной-ссылки изменить нельзя. При объявлении ссылки перед именем переменной ставится символ &. Ссылка при объявлении всегда должна быть проинициализирована.
Например:

int iV=12;
int &sV=iV;   // sV - ссылка
cout<< sV;  // sV равно 12
sV=22;            // значение iV 
                  // стало равно 22
sV++;             // sV и iV  стало равно 23
int *pV= &sV;     // указатель  на sV и iV

Преобразование типа указателя

Преобразование типа указателя происходит при различных операциях, таких как вызов процедуры, присваивание, инициализация и т.п.
Указатель типа void может быть преобразован к указателю любого другого типа только явным приведением типа. Но указатель любого типа может быть неявно преобразован к указателю типа void.
Это применяется для передачи параметров функции, если тип формального параметра не очевиден (он может быть указателем типа int * или типа float *). В этом случае в прототипе функции вместо явного задания типа записывается тип void.
Например:

Fx(void *px); // Прототип функции
Fx(pi);       // Вызов функции для int * pi
Fx(pf);       // Вызов функции для float * pf

В теле функции для работы с указателем следует использовать явное преобразование типа.
Например: (int *)px.

Типы, определяемые в пространствах имен

Пространство имен позволяет именовать группу переменных и методов.
Создание пространства имен указывается ключевым словом namespace.
Пример:

namespace S  // Пространство имен S
{ int i; }
void main()
{ S::i++;     // Обращение к переменной 
              // i  из пространства имен S
}

В языке C++ объявляемые пространства имен могут быть иерархически вложены друг в друга.
Например:

namespace Outer {    
  int iOuter1= 111;   
  int func(int j);
  namespace Inner {   
    int iInner1 = 222;   
  }
}

Для традиционных приложений можно использовать стандартную библиотеку C++, которая определяет дополнительный набор типов. Пространство имен стандартной библиотеки обозначается идентификатором std.
Для того чтобы иметь возможность обращаться к переменным или методам из пространства имен, можно использовать один из следующих способов:

  • имя соответствующей переменной или метода должно быть квалифицировано названием пространства имен (пространство имен указывается перед именем через два символа двоеточия). Например:
std::string s="Это строка";
  • имя библиотеки должно быть установлено как доступное оператором using. Например:
using namespace std;  // ...    
string s1="Строка s1";

Оператор using можно указывать как до метода main, так и внутри метода main (в этом случае переменные и методы пространства имен будут доступны без квалификации их имени сразу после выполнения оператора using).
Для управляемых расширений используются библиотеки среды NET Framework, реализованные как пространства имен. Пространство имен System предоставляет большой набор типов, реализованных как классы или структуры.

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г.Яндекс.Метрика