Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ответы по экзамену ЯП.doc
Скачиваний:
3
Добавлен:
25.08.2019
Размер:
534.02 Кб
Скачать

Int X,y,*px; // Описание целочисленных переменных X,y и

// указателя на целое значение px.

px = &x; // Значением переменной px станет адрес переменной x.

y = *px; // Переменная y приобретает значение "того",

// на что указывает px, т.е. значение переменной x.

    Таким образом, два оператора присваивания в примере эквивалентны одному оператору y=x;, и *px может появляться в любом выражении, в котором может встретиться х.

Операция "&" применима только к переменным: конструкции вида &(х-3) или &5 запрещены. А также нельзя получить адрес регистровой переменной.

Ни один "правильный" указатель не может иметь значения 0, поэтому равенство нулю значения указателя может служить сигналом о ненормальном завершении выполнения функции.

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

Присваивание значения указателя другому указателю того же типа.

"Операция" инициализации указателя. Операторы: char a; char *pa=&a; описывают символьную переменнуюa и указатель pa на объект типа char, а также инициализируют pa так, чтобы он указывал на a.

Операция вычитания указателей одного и того же типа.

Операции сложения и вычитания указателя и целого.

Операции сравнения указателей одного и того же типа. Если p и q - указатели на объекты одного типа, то к ним применимы операции отношения (<, >=, >, <=, !=, ==).

Например:

  • отношение p!=q истинно, если p и q указывают на разные объекты;

  • отношение p==q истинно, если p и q указывают на один и тот же объект.

Присваивание указателю нуля (NULL) и сравнение указателя с нулем (NULL). Например, отношениеp!=NULL истинно, если указатель p отличен от NULL.

    Пример 1. Проиллюстрируем выбор данных из памяти с помощью различных указателей.

#include <iostream.h>

void main()

{

unsigned long L=0x12345678L;

char *cp=(char *)&L;

int *ip=(int *)&L;

long *lp=(long *)&L;

cout << hex; //Шестнадцатеричное представление выводимых значений.

cout << "\n Адрес L, &L=" << &L;

cout << "\ncp = " << (void*)cp << "\t*cp = 0x" << (int)*cp;

cout << "\nip = " << (void *)ip << "\t*ip=0x" << *ip;

cout << "\nlp = " << (void *)lp << "\t*lp=0x" << *lp;

}.

Результат работы программы:

Адрес L, &L=0x243f2256

cp = 0x243f2256 *cp= 0x78

ip = 0x243f2256 *ip= 0x5678

lp = 0x243f2256 *lp= 0x12345678

В программе используется явное приведение типов. Так как адрес &L имеет тип unsigned long *, то при инициализации указателей его значение явно преобразуется соответственно к типам char *, int *, long *. При выводе значений указателей они преобразуются к типу void *, так как требуется вывод значений, а не длин участков памяти, связанных со значениями указателей.

При выводе значения *cp использовано явное преобразование типа (int), так как при его отсутствии будет выведен не код, а соответствующий ему символ ASCII-кода. Особенность размещения чисел в памяти компьютера заключается в том, что сначала размещаются младшие байты числа, а затем старшие.

  1. Массивы и указатели в языке C++. Многомерные массивы, массивы указателей, динамические массивы.

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

При определении массива ему выделяется память так же, как массивам других алгоритмических языков. Но как только память для массива выделена, имя массива воспринимается как константный указатель того типа, к которому отнесены элементы массива. Однако это справедливо не всегда. Например, при использовании имени массива в операции sizeof, ее результатом является размер в байтах участка памяти, выделенного не для указателя, а для массива в целом. Исключением является и применение операции & (получение адреса) к имени массива. Результат операции - адрес начального (с нулевым индексом) элемента массива. В остальных случаях значением имени является адрес первого элемента массива, которое нельзя изменить.

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

<тип элементов массива> <имя массива> [<количество элементов в массиве>];.

Нумерация элементов в массиве начинается с нуля!

Массивы могут иметь те же типы и классы памяти, что и простые переменные. В некоторых случаях допустимо описание массива без указания количества его элементов, то есть без константного выражения в квадратных скобках. Например: extern unsigned long UL[]; является описанием внешнего массива, который определен в другой части программы, где ему выделена память и (возможно) присвоены начальные значения его элементам. Приведем еще несколько примеров описания массивов:

char alpha[26]; //Внешний массив, содержащий 26 символов.

main ()

{

static int nan[22]; //Статический массив, содержащий 22 целых числа.

extern char alpha[]; //Внешний массив, размер его указан выше.

float a[15]; //Автоматический массив, содержащий 15

//вещественных чисел.

}

    В языке C++ определены только одномерные массивы. Многомерные массивы строятся на основе рекурсивного правила, согласно которому элементом массива может быть массив. Таким образом, в языке C++ двумерный массив(матрица) - это одномерный массив, каждый элемент которого является одномерным массивом.

При определении массива может выполняться его инициализация, то есть элементы массива получают конкретные значения. Инициализация выполняется по умолчанию, если массив статический или внешний. В этих случаях всем элементам массива компилятор автоматически присваивает нулевые значения. Явная инициализация элементов массива разрешена только при его определении и возможна двумя способами: либо с указанием размера массива в квадратных скобках, либо без явного указания (без конкретного выражения) в квадратных скобках, например:

char СН[ ] = { 'А', 'В', 'С', 'D'}; // Массив из 4 элементов.

int pr[6]= {10,20,30,40}; // Массив из 6 элементов.

char St[ ] = "ABCD"; // Массив из 5 элементов (включая нулевой элемент).

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

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

extern float E[ ]; // Правильное описание внешнего массива.

Предполагается, что в месте определения массива для него выделена память и выполнена инициализация.

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

Имя массива является указателем-константой, значением которой служит адрес первого элемента массива (с индексом 0). Таким образом, доступ к первому элементу массива может быть осуществлен так:

<имя массива>[0]

или

*<имя массива> .

    В общем случае доступ к заданному элементу массива можно осуществить двумя способами:

<имя массива>[<номер элемента>]

или

*(<имя массива>+<номер элемента>).

В языке C++ нет специального типа днных "строка". Вместо этого каждая символьная строка в памяти компьютера представляется в виде одномерного массива типа char, последним элементом которого является символ '\0'. Изображение строковой константы может использоваться по-разному. Если строка применяется для инициализации массива типа char, например, так: char array[ ] = "инициализирующая строка";, то адрес первого элемента строки становится значением указателя-константы (имени массива) array. Если строка используется для инициализации указателя типа char *: char *pointer = "инициализирующая строка" ;, то адрес первого элемента строки становится значением указателя-переменной pointer. Если использовать строку в выражении, где разрешено применять указатель, то используется адрес первого элемента строки:

char * string;

string = "строковый литерал";

В данном примере значением указателя string будет не вся строка "строковый литерал", а только адрес ее первого элемента. 

Многомерный массив представляет собой массив массивов, то есть массив, элементами которого служат массивы. Определение многомерного массива в общем случае должно содержать сведения о типе, размерности и количествах элементов каждой размерности, например описание: int ARRAY[4][3][6]; определяет массив, состоящий из четырех элементов, каждый из которых - двухмерный массив с размерами 3 на 6. В памяти массив ARRAY размещается в порядке возрастания самого правого индекса, то есть самый младший адрес имеет элемент ARRAY[0][0][0], затем идет элемент ARRAY[0][0][1] и т.д.

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

int ARRAY [4][3][6] = {0,1,2,3,4,5,6,7}

инициализирует только первые 8 элементов этого массива:

ARRAY[0][0][0]=0, ARRAY[0][0][1]=1, ARRAY[0][0][2]=2, ARRAY[0][0][3]=3,

ARRAY[0][0][4]=4, ARRAY[0][0][5]=5, ARRAY[0][1][0]=6, ARRAY[0][1][1]=7.

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

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

    Заметим, что в языке C++ гарантируется, что ни один "правильный" указатель не может иметь значение 0. Так что возвращение нуля в качестве значения указателя может служить сигналом о ненормальном завершении функции.

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