ТОП 10:

Многомерные массивы. Инициализация многомерных массивов.



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

После выполнения этого оператора массив в переменной sizes имеет четыре элемента с индексами (0, 0), (0, 1), (1, 0) и (1, 1), содержащие значения по умолчанию. При подобном создании массива необходимо использовать последовательный оператор присваивания, чтобы присвоить каждое значение элемента. После объявления поставьте знаком равенства (=) и укажите предложение New (Visual Basic

Индексы верхних границ можно инициализировать только в одном расположении.

В предложении New укажите каждый индекс верхней границы в скобках и передавайте значения элементов внутри фигурных скобок ({}). В следующем примере объявляется, создается и инициализируется переменная для хранения двумерного массива с элементами типа Short, указываются верхние границы и значения. Обратите внимание на два уровня фигурных скобок в предложении New.

Dim startingScores(,) As Short = New Short(1, 1) {{10, 10}, {10, 10}}. После выполнения этого оператора массив в переменной startingScores содержит четыре инициализированных элемента. В предложении New оставьте скобки пустыми, необходимы только запятые для соответствующего числа измерений, значения элементов указываются внутри фигурных скобок ({}). В следующ примере объявляется, создается и инициализ-ся переменная для хранения двумерн массива с эл-ми Тип данных Single (Visual Basic); указываются только значения элементов. Обратите внимание на два уровня фигурных скобок в предложении New.Dim diagonal(,) As Single = New Single(,) {{1, 0}, {0, 1}}. После выполнения этого оператора массив в переменной diagonal содержит четыре инициализированных элемента.


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

Структура – это способ связать воедино данные разных типов и создать пользовательский тип данных.

Структура – тип данных, задаваемый пользователем. В общем случае при работе со структурами следует выделить четыре момента: - объявление и определение типа структуры, - объявление структурной переменной, - инициализация структурной переменной, - использование структурной переменной.

Определение типа структуры представляется в виде

struct ID

{

<тип> <имя 1-го элемента>;

<тип> <имя 2-го элемента>;

…………

<тип> <имя последнего элемента>;

};

Определение типа структуры начинается с ключевого слова struct и содержит список объявлений, заключенных в фигурные скобки. За словом struct следует имя типа, называемое тегом структуры (tag – ярлык, этикетка). Элементы списка объявлений называются членами структуры или полями. Каждый элемент списка имеет уникальное для данного структурного типа имя. Однако следует заметить, что одни и те же имена полей могут быть использованы в различных структурных типах.

Определение типа структуры представляет собой шаблон (template), предназначенный для создания структурных переменных.

Объявление переменной структурного типа имеет следующий вид: struct ID var1;

при этом в программе создается переменная с именем var1 типа ID. Все переменные, использующие один шаблон (тип) структуры, имеют одинаковый набор полей, однако различные наборы значений, присвоенные этим полям. При объявлении переменной происходит выделение памяти для размещения переменной. Шаблон структуры позволяет определить размер выделяемой памяти.

Структуры нельзя сравнивать. Сравнивать можно только значения конкретных полей.

Вложенные структуры.Полем структурной переменной может быть переменная любого типа, в том числе другая структурная переменная. Поле, представляющее собой структуру, называется вложенной структурой. Тип вложенной структуры должен быть объявлен раньше. Кроме того, структура не может быть вложена в структуру того же типа. Объявление вложенной структуры:

struct point

{

int x,y;

};

struct rect

{

struct point LUPoint, RDPoint;

char BorderColor[20];

};

struct rect Rect;

В переменной Rect два поля LUPoint (точка, соответствующая левому верхнему углу прямоугольника) и RDPoint (точка, соответствующая правому нижнему углу) представляют собой вложенные структуры. Для доступа к полю вложенной структуры следует сначала обратится к внешней структуре, затем к вложенной: Rect.LUPoint.x.

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

struct rect Rect={10,5,50,25,"White"};

printf("Параметры прямоугольника:\n");

printf("Координаты левого верхнего угла %d %d\n", Rect.LUPoint.x, Rect.LUPoint.y);

printf("Координаты левого верхнего угла %d %d\n", Rect.RDPoint.x, Rect.RDPoint.y);

printf("Цвет границы: %s\n", Rect.BorderColor);

Структуры, имеющие в своем составе поля-указатели на такую же структуру, используются для создания сложных структур данных – списков, деревьев.

 

При необходимости хранения некоторых данных в виде нескольких массивов одной размерности, но разного типа, возможна организация массива структур. Наглядно массив структур можно представить в виде таблицы, где столбцы таблицы представляют собой поля структуры, а строки – элементы массива структур.

Например, имеется два разнотипных массива:

char c[N];

int i[N];

Объявление

struct key

{

char c;

int i;

} keytab[N];

создает тип структуры key и объявляет массив keytab[N], каждый элемент которого есть структура типа key.

Возможна запись:

struct key

{

char c;

int i;

};

struct key keytab[N];

Инициализация массива структур выполняется следующим образом:

struct key

{

char c;

int i;

} keytab[]={

'a', 0,

'b', 0

};

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

Битовое поле.

В противоположность другим компьютерным языкам С имеет возможность, называемую битовыми полями, позволяющую работать с отдельными битами. Битовые поля полезны по нескольким причинам. Ниже приведены три из них: 1 Если ограничено место для хранения информации, можно сохранить несколько логических (истина/ложь) переменных в одном байте. 2 Некоторые интерфейсы устройств передают информацию, закодировав биты в один байт. 3 Некоторым процедурам кодирования необходимо получить доступ к отдельным битам в байте. Хотя все эти функции могут выполняться с помощью битовых операторов, битовые поля могут внести большую ясность в программу.

Метод использования битовых полей для доступа к битам основан на структурах. Битовое поле, на самом деле, - это просто особый тип структуры, определяющей, какую длину имеет каждый член. Стандартный вид объявления битовых полей следующий:

struct имя структуры {

тип имя1: длина;

тип имя2: длина;

...

тип имяN: длина;

}

Битовые поля должны объявляться как int, unsigned или signed. Битовые поля длиной 1 должны объявляться как unsigned, поскольку 1 бит не может иметь знака. Битовые поля могут иметь длину от 1 до16 бит для 16-битных сред и от 1 до 32 бит для 32-битных сред.

 

 

Объединение – это тип данных, позволяющий переменным различного типа использовать одну и ту же область памяти. Для объявления объединения используется ключевое слово union. Объединение, так же как и структура, содержит несколько полей. Однако в любой момент времени доступно только одно поле. Под объединение выделяется столько памяти, сколько требуется для размещения самого большого поля. Все поля поочередно используют выделенную память для хранения своих значений. Определение типа:

union tag

{

тип1 переменная1;

тип2 переменная2;

……

};

где tag – имя типа.

Объявление переменной:

union tag u1;

или

union tag

{

тип1 переменная1;

тип2 переменная2;

……

} u1;

При обращении к полям объединения следует помнить, какое поле размещалось в памяти последним. Если пытаться извлекать данные с помощью поля другого типа, значение может быть прочитано неправильно.

Пример

union tag

{

int i;

double d;

} u={1.2};

printf("%d\n",u.i); //Вывод на экран числа 1

printf("%lf\n",u.d); //Вывод на экран числа 0

Ответ «1» получен потому, что инициализация должна соответствовать типу первого поля – int; ответ «0» – ледствие того, что данные типа int прочитаны полем типа float неправильно.

Перечисления- это набор именованных целочисленных констант, определяющий все допустимые значения, которые может принимать переменная. Перечисления можно встретить в повседневной жизни. Например, в качестве перечислений монет в Соединенных Штатах используются: один цент, пять центов, десять центов, двадцать пять центов, полдоллара, доллар

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

enum ярлык { список перечислений} список переменных;

Как имя перечисления - ярлык, так и список переменных необязательны, но один из них должен присутствовать. Список перечислений - это разделенный запятыми список идентификаторов. Как и в структурах, ярлык используется для объявления переменных данного типа. Следующий фрагмент определяет перечисление coin и объявляет переменную money этого типа:

enum coin { penny, nickel, dime, quarter, half_dollar, dollar);

enum coin money;

Имея данное определение и объявление, следующий тип присваивания совершенно корректен:

money = dime;

if (money==quarter) printf("is a quarter\n");

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

printf("The value of quarter is %d ", quarter); совершенно корректно.

Если явно не проводить инициализацию, значение первого символа перечисления будет 0, второго - 1 и так далее. Следовательно: printf("%d %d", penny, dime); выводит 0 2 на экран.

Указатель – это переменная, значением которой является адрес некоторого объекта (обычно другой переменной) в памяти компьютера. Подобно тому, как переменная типа char имеет в качестве значения символ, а переменная типа int – целочисленное значение, переменная типа указателя имеет в качестве значения адрес ячейки оперативной памяти. Допустимые значения для переменной-указателя – множество адресов оперативной памяти компьютера. Указатель является одной из наиболее важных концепций языка C. Правильное понимание и использование указателей особенно необходимо для составления хороших программ по следующим причинам: · указатели являются средством, при помощи которого функции могут изменять значения передаваемых в нее аргументов; · при помощи указателей выполняется динамическое распределение памяти; · указатели позволяют повысить эффективность программирования; · указатели обеспечивают поддержку динамических структур данных (двоичные деревья, связные списки).

Однако указатель может вызвать и ряд затруднений, например, если указатель содержит неправильное значение, программа может быть неработоспособной. Можно легко ошибиться при использовании указателей; к тому же ошибки, связанные с неправильными значениями указателей, найти очень трудно.

Итак, указатель – это новый тип данных. Для него определены понятия константы, переменной, массива. Как и любую переменную, указатель необходимо объявить. Объявление указателя состоит из имени базового типа, символа * (звездочка) и имени переменной.

Общая форма объявления указателя: тип *имя;

Тип указателя определяет тип объекта, на который указатель будет ссылаться, например, int *p1;

Фактически указатель любого типа может ссылаться на любое место в памяти, но выполняемые над указателем операции существенно зависят от его типа. Так, если объявлен указатель типа int *, компилятор предполагает, что любой адрес, на который он ссылается, содержит переменную типа int, хотя это может быть и не так. Следовательно, объявляя указатель, необходимо убедиться в том, что его тип совместим с типом объекта, на который он будет ссылаться.

Указатели и массивы

В языке C массивы и указатели тесно связаны друг с другом. Например, когда объявляется массив в виде int a[25], то при этом не только выделяется память для 25 элементов массива, но и формируется указатель с именем a, значение которого равно адресу первого по счету (нулевого) элемента массива. Доступ к элементам массива может осуществляться через указатель с именем a. С точки зрения синтаксиса языка указатель a является константой, значение которой можно использовать в выражениях, но изменить это значение нельзя.

Поскольку имя массива является указателем-константой, допустимо, например, такое присваивание:

int a[25]; // int *ptr; // ptr=a;

В этом примере в переменную-указатель ptr записывается адрес начала массива a, т. е. адрес первого элемента массива.

Также справедливы следующие соотношения: например, имеется массив a[N], тогда истинными будут следующие сравнения:

a==&a[0]; // *a==a[0].

Указатели можно увеличивать или уменьшать на целое число:

ptr=a+1;

Теперь указатель ptr будет указывать на второй элемент массива a, что эквивалентно &a[1].

При увеличении указателя на единицу адрес, который он представляет, увеличивается на размер объекта связанного с ним типа, например:

int a[25]; // int *ptr=a; // ptr+=3;

Первоначально указатель ptr указывал на начало массива a. После прибавления к переменной ptr числа 3 значение указателя увеличилось на 3*sizeof(int), а указатель ptr теперь будет указывать на четвертый элемент массива a.

Таким образом, в языке C для доступа к элементам массива существует два различных способа. Первый способ связан с использованием обычных индексных выражений в квадратных скобках, например, a[7]=3 или a[i+2]=5. При таком способе доступа записываются два выражения, причем второе выражение заключается в квадратные скобки. Первое из этих выражений должно быть указателем, а второе – выражением целого типа. Указатель, используемый в индексном выражении, не обязательно должен быть константой, указывающей на какой-либо массив, это может быть и переменная-указатель. В частности, после выполнения присваивания ptr=a доступ к седьмому элементу массива можно получить как с помощью константы-указателя a в форме a[7], так и переменной-указателя ptr в форме ptr[7].

Операция получения адреса

Понятие указателя тесно связано с понятием адреса объекта. В C есть специальная операция, позволяющая получить адрес любой переменной: &p – получение адреса, где p – идентификатор переменной. Результатом операции является адрес переменной p. Пример программы:

# include <stdio.h> // int main() // { // int x=2,*p; // p=&x;

printf("\n x=%d address of x=%u",x,p); // return 0; // }

Понятие переменной типа указатель также связано с операцией косвенной адресации *, называемой еще операцией разыменования, которая имеет структуру: *р – разыменование, где р – идентификатор переменной-указателя. Эта запись означает, что в ячейку с адресом, записанным в переменную р, помещено значение некоторой величины.

Операторы ptr=&a; и val=*ptr; равнозначны оператору val=a;

Например,

n=32;

p=&n; /* p–адрес ячейки, куда записано n */

v=*p;

В результате выполнения этих действий в переменную v будет помещено число 32.

Операции над указателями

Над указателями определено 5 основных операций.

§ Определение адреса указателя: &p, где p – указатель (&p – адрес ячейки, в которой находится указатель).

§ Присваивание. Указателю можно присвоить адрес переменной p=&q, где p – указатель, q – идентификатор переменной.

§ Определение значения, на которое ссылается указатель: *p (операция косвенной адресации).

§ Увеличение (уменьшение) указателя. Увеличение выполняется как с помощью операции сложения (+), так и с помощью операции инкремента (++). Уменьшение – с помощью операции вычитания (–) либо декремента (––).

Например, пусть p1 – указатель, тогда р1++ перемещает указатель на:

o 1 байт, если *p1 имеет тип char;

o 4 байта, если *p1 имеет тип int (в 32 разрядной операционной системе) или 2 байта (в 16 разрядной операционной системе);

o 4 байта, если *p1 имеет тип float.

§ Разность двух указателей. Пусть р1 и р2 – указатели одного и того же типа. Можно определить разность р1 и р2, чтобы найти, на каком расстоянии друг от друга находятся элементы массива.

Далее смотрим вопрос 50.

Операции адресной арифметики (вопрос 50) подчиняются следующим правилам. После увеличения значения переменной-указателя на 1 данный указатель будет ссылаться на следующий объект своего базового типа. После уменьшения – на предыдущий объект. Для всех указателей адрес увеличивается или уменьшается на величину, равную размеру объекта того типа, на который они указывают. Поэтому указатель всегда ссылается на объект с типом, тождественным базовому типу указателя.

Применительно к указателям на объект типа char операции адресной арифметики выполняются как обычные арифметические операции, потому что длина объекта char всегда равна 1.

Операции адресной арифметики не ограничены увеличением (инкрементом) и уменьшением (декрементом). К указателям, например, можно добавлять или вычитать из них целые числа.

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

Все остальные операции над указателями запрещены.

 

51 Распределение памяти.Память для хранения данных может выделяться как статически, так и динамически. В первом случае выделение памяти выполняет компилятор, встретивший при компиляции объявление объекта. В соответствии с типом встретившегося объекта вычисляется объем памяти, требуемый для его размещения. Класс памяти задает место, где эти объекты (данные) будут располагаться. Это может быть сегмент данных либо стек. Напомним, что стек (магазин, список LIFO – Last In First Out) представляет собой последовательный список переменной длины, в котором включение и исключение элементов производится только с одной стороны. Главные операции при работе со стеком – включение и исключение элемента – осуществляются с вершины стека, причем в каждый момент доступен элемент, находящийся на вершине стека.

Часто возникают ситуации, когда заранее не известно, сколько объектов – чисел, строк текста и прочих данных будет хранить программа. В этом случае используется динамическое выделение памяти, когда память занимается и освобождается в процессе исполнения программы. При использовании динамической памяти (ДП) отпадает необходимость заранее распределять память для хранения данных, используемых программой. Управление динамической памятью – это способность определять размер объекта и выделять для его хранения соответствующую область памяти в процессе исполнения программы.

При динамическом выделении памяти для хранения данных используется специальная область памяти, так называемая «куча» (heap). Объем «кучи» и ее местоположение зависят от модели памяти, которая определяет логическую структуру памяти программы (гл. 8).

Функции, выполняющие динамическое распределение памяти в «куче», и заголовочные файлы, в которых эти функции объявлены, представлены в табл. 14.1.

При каждом обращении к функции распределения памяти выделяется запрошенное число байт. Адрес начала выделенной памяти возвращается в точку вызова функции и записывается в переменную-указатель. Созданная таким образом переменная называется динамической переменной. Распределенная память гарантируется от повторного выделения при следующих обращениях за байтами памяти. Дальнейшая работа с выделенной областью осуществляется через переменную-указатель, хранящую адрес выделенной области памяти. Сама же переменная остается безымянной.

Если выделенный участок памяти больше не требуется, он может быть освобожден. При высокой активности по динамическому распределению памяти «куча» фрагментируется. Для смягчения отрицательных последствий фрагментации служат функции повторного распределения памяти. Они пытаются либо расширить, либо уменьшить размер ранее выделенного блока памяти.

Функции управление памятью.Рассмотрим функции управления памятью:

· malloc() – предназначена для выделения непрерывной области памяти заданного размера, например, void * malloc(size_t size),

где size_t – тип результата операции sizeof, определяемый в различных объектах-заголовках (stdio.h,stdlib.h,string.h и др.) и соответствующий типу unsigned long; size – размер выделяемой памяти в байтах.

Функция malloc возвращает указатель без типа. Если выделить память не удалось, функция возвращает значение NULL.

При использовании в программах на C++ требуется выполнять явное преобразование типа указателя. Если необходимо создать символьную cтроку в динамической памяти, то сначала надо объявить указатель char *S1, а затем выделить область под символьную строку с помощью функции

malloc():

S1=(char*)malloc(V);

где V – выражение, значением которого является целые неотрицательные числа, например, V=10, V=10+7 и т. д.

Далее указатель S1 используется в функциях для работы со строками так же, как если бы строка была объявлена как массив символов или указатель на статическую строку, например:

gets (S1); // scanf ("%s",S1); // printf ("%s",S1); // int n=strlen(S1);

· calloc() – предназначена для выделения памяти под заданное количество объектов, каждый из которых имеет размер size байт, всего n ´ size байт. Возвращает указатель на первый байт выделенной область памяти.

Если выделить память не удалось, функция возвращает значение NULL:

void * calloc(size_t n, size_t size);

· realloc() – предназначена для изменения размера динамически выделенной области, адресуемой указателем ptr, при этом размер области может как увеличиваться, так и уменьшаться:

void* realloc(void* ptr, size_t size);

где ptr – указатель на первоначальную область памяти, size – новый размер области памяти.

Функция возвращает адрес новой области памяти, при этом старая область освобождается. Данные из освобождаемой области копируются в новую, но не более size байт. В некоторых случаях область, адресуемая первоначально указателем ptr, может сохраниться, только изменится ее размер. Если выделить память не удалось, функция возвращает значение NULL.

Для того чтобы избежать ошибок в связи с перемещением данных в динамической памяти, функцию realloc() следует использовать так:

ptr2=realloc(ptr1,new_size);

if(ptr2!=NULL) /*Проверка выделения новой памяти*/

ptr1=ptr2; /*Запись адреса новой области памяти в исходный указатель*/

Таким образом, указатель ptr1 всегда будет хранить текущий адрес размещения данных, независимо от того, были данные перемещены функцией realloc() или нет.

· free() – предназначена для освобождения памяти, выделенной функциями malloc(),calloc(),realloc(). После выполнения функции освобожденная память может быть выделена вновь под другие данные:

void free(void* ptr);

где prt – указатель на область памяти, созданной только функциями динамического управления памятью malloc(),calloc(),realloc(). Использование других указателей в функции free делает ее поведение неопределенным и может привести к потере управления памятью.

В заключение отметим, что в программах, использующих язык C++, рекомендуется для управления динамической памятью использовать средства именно этого языка – операторы new и delete, которые будут рассмотрены позже.

Динамическим называется массив, размер которого может меняться во время исполнения программы. Для изменения размера динамического массива язык программирования, поддерживающий такие массивы, должен предоставлять встроенную функцию или оператор. Динамические массивы дают возможность более гибкой работы с данными, так как позволяют не прогнозировать хранимые объёмы данных, а регулировать размер массива в соответствии с реально необходимыми объёмами. В отличие от динамических массивов существуют статические массивы и массивы переменной длины. Размер статического массива определяется на момент компиляции программы. Размер массива переменной длины определяется во время выполнения программы. Отличием динамического массива от массива переменной длинны является автоматическое изменение размеров, что не трудно реализуется в случаях его отсутствия, поэтому часто не различают массивы переменной длины с динамическими массивами.

Пример объявления динамического массива на языках C/C++[править]

Одномерный динамический массив:

Создаем массив с 10-ю элементами типа int:

int *mas = new int[10];

Получить доступ к значению каждого элемента можно по индексу (порядковый номер):

mas[0] = 2; // присвоили значение 2 нулевому элементу массива mas

mas[1] = 7; // присвоили значение 7 первому элементу массива mas

//... и т.д.

Следовательно, если брать такой подход, то вам понадобится около десяти строк кода, чтобы проинициализировать весь массив. Для того, чтобы этого избежать, напишем то же самое в цикле:

for(int i = 0; i < 10; i++){

cin>>mas[i]; // пользователь вводит значение каждого i-ого элемента массива

}

После чего работаем с массивом. Так же его можно вывести на экран:

for(int i = 0; i < 10; i++){

cout << mas[i] << endl; }

Для освобождения из памяти одномерного динамического массива используем: оператор delete:

delete []mas;

Строго говоря вышеописанная реализация массива не является динамической, т.к. нет изменения размера массива во время работы, а всего лишь массив переменной длины. Возможным решением является realloc, но можно применить только при использовании malloc, но не new. Для того чтобы изменить размер такого массива необходимо объявить ещё один массив нужного размера, скопировать в него все данные и освободить память, занимаемую старым массивом. В С++ библиотечным решением является std::vector. В С89 нет массивов переменной длины, они есть только в С99 (который поддерживают не все компиляторы). Некоторые (довольно старые) компиляторы С++ также не поддерживают массивов переменной длины.

 


typedef вводит новое имя (синоним) для существующего типа.

С помощью typedef может быть объявлен любой тип, включая типы функции или массива.

typedef double (* MATH)(); // MATH - новое имя типа, представляющее указатель на

//функцию, возвращающую значения типа double

MATH cos; // cos - это указатель на функцию, возвращающую значения типа double

 

Можно привести эквивалентное объявление - double (* cos)();

typedef char SIMB[40]; //SIMB - массив из сорока символов

SIMB person; //переменная person - тоже массив из сорока символов

Это эквивалентно объявлению - char person[40];

Помимо этого, имена типов могут использоваться еще и в списке формальных параметров (в объявлении функций), в операциях приведения типов и в операции sizeof.

typedef способен весьма облегчить нам жизнь. И не только нам...

typedef можно использовать, чтобы значительно упростить синтаксис сложных объявлений (воззаботимся же, братия, о тех бедных программистах, которые приИдут после нас). Используя typedef, можно сделать простым даже объявление стандартной функции set_new_handler:

typedef void (*new_handler)();

new_handler set_new_handler(new_handler);

Операция sizeof

Существует два раздельных способа использования операции sizeof:

sizeof унарное-выражение

sizeof (имя-типа)

Размер выделяемой для каждого типа памяти зависит от конкретной машины.

В обоих сучаях результат представляет собой целочисленную константу, выражающую размер в байтах области памяти, занимаемой операндом (определяемый за некоторыми исключениями типом операнда). В первом случае тип выражения операнда определяется без расчета выражения (и следовательно, без побочных эффектов). Если операнд имеет тип char (signed или unsigned), то операция sizeof дает в результате 1. Если операнд не является параметром и имеет тип масива, то результат представляет собой общее количество байтов в массиве (другими словами, имя массива не преобразовавается к типу указателя). Число элементов массива равно sizeof массив/sizeof массив[0]. Если операнд является параметром, объявленным как массив или функция, sizeof дает размер указателя. Применительно к структурам и объединениям sizeof дает общее число байтов, включающее любые символы-заполнители.

Целочисленный тип результата операции sizeof называется size_t, определенный как unsigned int в stddef.h.

Можно использовать sizeof в директивах препроцессора; это особенность Turbo C++.

C++: В С++ sizeof(тип класса), где тип класса является производным от какого-либо базового класса, возвращает размер базового класса.

Функцию можно рассматривать как операцию, определенную пользователем. В общем случае она задается своим именем. Операнды функции, или формальные параметры, задаются в списке параметров, через запятую. Такой список заключается в круглые скобки. Результатом функции может быть значение, которое называют возвращаемым. Возвращаемое значение указывается в операторе return в теле функции. Подобно передаче параметров, операция возвращения значения функции эквивалентна инициализации. Считается, что оператор return инициализирует переменную, имеющую тип возвращаемого значения. Об отсутствии возвращаемого значения сообщают ключевым словом void. Действия, которые производит функция, составляют ее тело; оно заключено в фигурные скобки. Использование функций требует что бы функция была сначала объявлена, а потом определена. Объявление функции сообщает компилятору тип возвращаемого значения, тип параметров и как функция работает, и называется прототипом функции. Вызов функции может обрабатываться двумя разными способами. Если она объявлена встроенной (inline), то компилятор подставляет в точку вызова ее тело. Во всех остальных случаях происходит нормальный вызов, который приводит к передаче управления ей, а активный в этот момент процесс на время приостанавливается. По завершении работы выполнение программы продолжается с точки, непосредственно следующей за точкой вызова.

 

54При передаче данных по значению функция работает с копиями фактических параметров, и доступна к исходным значениям аргументов у нее нет. При передачи по адресу в функцию передается не переменная, а ее адрес, и, следовательно, функция имеет доступ к ячейкам памяти, в которых хранятся аргументов. Таким образом, данные, переданные по значению, функция изменить не может, в отличие от данных, переданных по адресу. Возможен и другой способ передачи параметров - вызов по ссылке. В случае вызова по ссылке оператор вызова дает вызываемой функции возможность прямого доступа к передаваемым данным, а также возможность изменения этих данных. Вызов по ссылке хорош в смысле производительности, потому что он исключает накладные расходы на копирование больших объемов данных; в го же время он может ослабить защищенность, потому что вызываемая функция может испортить передаваемые в нее данные. Вызов по ссылке можно осуществить двумя способами: с помощью ссылочных параметров и с помощью указателей.

 

55 Внутри функции могут быть объявлены переменные, как, например, переменные p и i в функции power. Такие переменные называются локальными и они определены только внутри этой функции. Переменные, определенные вне тела любой функции (ранее мы такие переменные вообще не рассматривали) называются глобальными и они определены всюду начиная с места определения и до конца файла. Переменные, в которых сохраняются параметры, передаваемые функции, также являются локальными для этой функции. Эти переменные создаются при вызове функции и в них копируются значения, передаваемые функции в качестве параметров. Эти переменные можно изменять, но все изменения этих переменных будут "забыты" после выхода из функции.

 

56 Массив — упорядоченный набор данных, для хранения данных одного типа, идентифицируемых с помощью одного или нескольких индексов. В простейшем случае массив имеет постоянную длину и хранит единицы данных одного и того же типа. Если в качестве параметра функции указан массив, то передается указатель на его первый элемент. Это означает, что фактический параметр типа T[] преобразуется к типу T*, и затем передается. Поэтому присваивание элементу формального параметра-массива изменяет этот элемент. Иными словами, массивы отличаются от других типов тем, что они не передаются и не могут передаваться по значению.

 

57 Хотя функция - это не переменная, она все равно имеет физическое местоположение в памяти, которое может быть присвоено указателю. Адрес функции является входной точкой функции. Поэтому указатель на функцию может использоваться для вызова функции. В некоторых типах программ пользователь может выбирать некоторый вариант из списка возможных действий. Например, в системе подсчета может быть меню более чем с 20 вариантами. Когда выбор сделан, программа выполняет соответствующую функцию. Это может быть сделано двумя способами. Как правило, с этой целью используется оператор switch. Тем не менее в приложениях, где требуется высокая производительность, лучше применять другой способ. Можно использовать массив указателей, содержащих адреса функций. Выбор, сделанный пользователем, декодируется и используется для индексации массива указателей, вызывая выполнение необходимой функции. Этот метод гораздо быстрее, чем метод использования switch.

 

58 Один из способов, которым достигается реализация полиморфизма в языке С++, заключается в использовании перезагрузки функций. В C++ две или более функций могут иметь одно и то же имя в случае, если они отличаются набором параметров в интерфейсе. В таком случае о функциях говорят, что они перегружены. Перегрузка функций важна потому, что она помогает в решении проблемы сложности. Хотя можно использовать одно и то же имя для перегрузки функций, выполняющих совершен­но различные задачи, делать этого не следует. Например, можно использовать имя sqr_it() для создания функций, возвращающих квадрат целых чисел и квадратный корень чисел типа double. Тем не менее эти операции совершенно различны, и использование перегрузки функций в подоб­ных ситуациях противоречит самой идее перегрузки функций. В частности, перегрузку функций следует применять только для сходных между собой операций.

 

59 Класс памяти определяет порядок размещения объекта в памяти. Различают автоматический и статический классы памяти. C++ располагает четырьмя спецификаторами класса памяти: автоматический, регистровый, локальный, глобальный. Выбор класса памяти, помимо явных спецификаторов, зависит от размещения определения или объявления в тексте программы. Модуль, функция, блок могут включать соответствующие операторы объявления или определения, причём всякий раз определяемый объект будет размещаться в строго определённых областях памяти. Область действия объекта определяет, в каких участках программы допустимо использование имени этого объекта. Так, объект с глобальным временемжизни существует в течение всего времени выполнения программы, однако он доступен только в тех частях программы, на которые распространяется его область действия. Область действия объекта распространяется на блок или исходный файл, если в этом блоке или исходном файле известны тип и имя объекта

 







Последнее изменение этой страницы: 2016-08-14; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.234.244.18 (0.031 с.)