Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Манипуляторы и форматирование ввода-вывода↑ ⇐ ПредыдущаяСтр 4 из 4 Содержание книги
Поиск на нашем сайте
Часто бывает необходимо вывести строку или число в определенном формате. Для этого используются так называемые манипуляторы. Манипуляторы – это объекты особых типов, которые управляют тем, как ostream или istream обрабатывают последующие аргументы. Некоторые манипуляторы могут также выводить или вводить специальные символы. Например, один из манипуляторов - это endl. Он вызывает вывод символа новой строки. Другие манипуляторы позволяют задавать формат вывода чисел:
Использовать манипуляторы просто – их надо вывести в выходной поток. Предположим, мы хотим вывести одно и то же число в разных системах счисления: int x = 53;cout << "Десятичный вид: " << dec << x << endl << "Восьмиричный вид: " << oct << x << endl << "Шестнадцатиричный вид:" << hex << x << endl
Аналогично используются манипуляторы с параметрами. Вывод числа с разным количеством цифр после запятой: double x;// вывести число в поле общей шириной // 6 символов (3 цифры до запятой, // десятичная точка и 2 цифры после запятой)cout << setw(6) << setprecision(2) << x << endl;Те же манипуляторы (за исключением endl и ends) могут использоваться и при вводе. В этом случае они описывают представление вводимых чисел. Кроме того, имеется манипулятор, работающий только при вводе, это ws. Данный манипулятор переключает вводимый поток в такой режим, при котором все пробелы (включая табуляцию, переводы строки, переводы каретки и переводы страницы) будут вводиться. По умолчанию эти символы воспринимаются как разделители между атрибутами ввода. int x;// ввести шестнадцатиричное числоcin >> hex >> x; Указатели
В языке С++ существует два способа доступа к переменной - это ссылка на переменную по её имени и использование механизма указателей. Указатель-переменная (или просто указатель) это переменная, предназначенная для хранения адреса какой-либо переменной в памяти. Указатель-константа – это значение адреса оперативной памяти. В языке определены две специальные операции для доступа к переменным через указатели. Это операции & и операция *. Результатом операции & является выдача адрес объекта, к которому операция применяется. Например &var1 дает адрес, по которому переменная var1 хранится в памяти (точнее адрес её первого байта). Операция * - это операция обращения к содержимому памяти по адресу, хранимому в переменной-указателе или равному указателю константе. Признаком переменной-указателя для компилятора является наличие в описании переменной двух компонентов: ü Типа объекта данных, для доступа к которому используется указатель (или, как еще говорят, на который ссылается указатель). ü Символа * перед именем переменной. Сочетание типа данныйх и символа * воспринимается компилятором как особый тип данных – «указатель на что-либо». Таким образом, описание int var1,*ptr; приводит к появлению переменной var1 и указателя-переменной ptr. Здесь переменная ptr будет иметь тип int*, т.е. тип «указатель на целое». Указатели при их описании могут, как и обычные переменные, получать начальные значения: int var1,*ptr=&var1; Здесь указателю ptr присваивается начальное значение – адрес, по которому в памяти хранится переменная var1. Еще одна инициализация при описании: int *ptr=(int*)200; Операцию *, пытаясь выразить словами смысл выражения, можно заменить фразой: - «взять содержимое по адресу, равному значению указателя». Например, оператор присваивания *ptr2=*ptr1+4;
Можно интерпретировать так: взять содержимое памяти по адресу, равному значению указателя ptr1, прибавить к этому содержимому 4, а результат поместить по адресу, равному значению указателя ptr2. Сам указатель-переменная тоже имеет адрес. Поэтому, например, корректным будет фрагмент: int var1, *ptr1, *ptr2 = &var1; ptr1 = (int*)&ptr2;
Здесь описываются два указателя-переменные, Указатель ptr2 инициализируется значением адреса переменной var1. Затем указателю ptr1 присваивается значение адреса, по которому в памяти располагается указатель ptr2. Для указателей-переменных разрешены некоторые операции: присваивание, инкремент или декремент, сложение или вычитание, сравнение. Язык разрешает операцию сравнение указателей одинакового типа (!). При выполнении присваивания значение указателя в правой части выражения пересылается в ячейку памяти, отведенную для указателя в левой части. Важной особенностью арифметических операций с указателями является то, что физическое увеличение или уменьшение его значения зависит от типа указателя, т.е. от размера того объекта, на который ссылается указатель. Если к указателю, описанному как type *ptr, прибавить или отнять константу N, значение ptr изменяется на N* sizeof(type). Разность двух указателей type *ptr1 и type *ptr2 – это разность их значений, поделенная на sizeof(type). В частности, арифметические операции над указателями типа char* (размер типа равен 1) выполняются как над обычными целыми числами с той лишь разницей, что значения, участвующие в операции, - это адреса в оперативной памяти. Однако для других типов это не так. Например:
void main(void) { long *ptr1=(long*)100; long *ptr2=(long*)200; ptr1++; ptr2-=10; printf(“ptr2=%ld,ptr1=%ld, ptr2-ptr1=%ld\n”, ptr2,ptr1,ptr2-ptr1); } Результат: ptr2=160,ptr1=104,ptr2-ptr1=14
Так как указатель имеет тип long* (длина 4 байта), то «единица измерения» указателя равна 4 байтам. В самом деле: ptr1=100+1*4=104. ptr2=200-10*4=160. ptr2-ptr1=(160-104)/4=56/4=14.
Для чего нужны указатели? Указатели появились, прежде всего, для нужд системного программирования. Поскольку язык Си предназначался для "низкоуровневого" программирования, на нем нужно было обращаться, например, к регистрам устройств. У этих регистров вполне определенные адреса, т.е. необходимо было прочитать или записать значение по определенному адресу. Благодаря механизму указателей, такие операции не требуют никаких дополнительных средств языка. int *ptr=(int*)200;
Однако использование указателей нуждами системного программирования не ограничивается. Указатели позволяют существенно упростить и ускорить ряд операций. Предположим, в программе имеется область памяти для хранения промежуточных результатов вычислений. Эту область памяти используют разные модули программы. Вместо того, чтобы каждый раз при обращении к каждому конкретному модулю копировать эту область памяти, мы можем передавать указатель на эту область в качестве аргумента вызова функции, тем самым упрощая и ускоряя вычисления. Упомянутые в лекции примеры использования указателей никак не связаны с объектно-ориентированным программированием. Казалось бы, объектно-ориентированное программирование должно уменьшить зависимость от низкоуровневых конструкций типа указателей. На самом деле программирование с классами нисколько не уменьшило потребность в указателях, и даже наоборот, нашло им дополнительное применение, о чем будет рассказано в следующих лекциях.
Массивы
Массив – это один из структурированных типов данных. Это расположенные вплотную друг за другом в памяти элементы одного и того же типа. Каждый массив имеет имя. Доступ к отдельным элементам массива осуществляется по имени массива и индексу (порядковому номеру) элемента. Основные свойства массива: ü Все элементы массива имеют один и тот же тип; ü Все элементы массива расположены в памяти друг за другом; индекс первого элемента равен НУЛЮ. ü Имя массива является указателем-константой, равной адресу начала массива (первого байта первого элемента массива) Признаком массива при описании является наличие парных квадратных скобок [ ]. Константа или константное выражение в скобках задает число элементов массива. Например: char array[81]; int key[4];
При описании массива может быть выполнена инициализация его элементов. Существуют два метода инициализации массивов. ü Инициализация по умолчанию. Это случай, когда все элементы массивов инициализируются нулями. ü Явная инициализация элементов. Это случай, когда после описания массива помещается список начальных значений элементов массива, заключенный в фигурные скобки. Существуют две формы явной инициализации элементов массива: 1) Явное указание числа элементов массива и список начальных значений, возможно, с меньшим числом элементов. Например: char array[10]={‘A’,’B’,’C’,’D’};
Здесь описывается массив из 10 элементов. Первые 4 элемента массива инициализируются символами ’A’,’B’,’C’,’D’. Значение остальных шести элементов либо равно нулю, либо не определено (в зависимости от способа объявления массива). Если список начальных значений содержит больше элементов, чем число в квадратных скобках, компилятор генерирует ошибку. 2) Неявное указание числа элементов массива со списком начальных значений. Компилятор определяет число элементов массива по списку инициализации. Например:
char array[]={’A’,’B’,’C’,’D’};
В результате создается массив ровно из 4 элементов, и эти элементы получают начальные значения из списка инициализации.
Если при описании массива отсутствует значение в квадратных скобках и список начальных значений, компилятор обычно регистрирует ошибку. Однако в тех контекстах, где не требуется резервирование места в памяти под массив, этого не происходит. Эти случаи следующие:
1. Если массив объявляется как внешний, при этом в том месте, где массив описывается приведена информация о числе его элементов. Например: extern char array[]; 2. в описании функции, если указатель на первый элемент массива является аргументом функции. Например: int function (int array[], int index) { // тело функции } 3. В прототипах функций, использующих в качестве аргумента указатель на первый элемент массива.
Доступ к отдельным элементам массива может выполняться либо с помощью индекса, либо операцией взятия значения по адресу. В первом случае для ссылки на нужный элемент указывается его порядковый номер в массиве, заключенный в квадратные скобки. Самый первый элемент массива имеет порядковый номер 0. Например:
int array[]={1,2,3,4,5}; int index = 0, first, last, bad; first = array[index]; // first = 1 last = array[4]; // last = 5 bad = a[index+6]; // bad случайно
В С++ для повышения производительности программы не выполняются многие проверки корректности вычислений, в том числе и контроль допустимости значения индекса массива. Поэтому в приведенном примере значение bad - это содержимое двух байтов памяти сразу после описанного массива a. Содержимое этих байтов случайно. Для упрощения контроля границ индекса массива удобно использовать операцию sizeof, которая применительно к массивам возвращает чмсло байтов памяти, зарезервированных компилятором для массива. Например, так можно определить число элементов массива:
int array[10]={1,2,3,4,5,6,7}; int members; members=sizeof(array)/sizeof(int);
Нетрудно догадаться, что переменная members будет равна 10. Другой способ доступа к элементам массива – использование механизма указателей. Так как имя массива – это указатель-константа на первый байт первого элемента массива, то, используя операцию взятия значения по адресу, можно выполнить доступ к любому из элементов массива. Так следующие выражения являются тождествами:
array тождественно &array[0], (array+i) тождественно &array[i]. Использование указателей для доступа к элементам массива дает несколько более короткий код программы и в ряде случаев позволяет обойтись без дополнительных переменных, используемых в качестве индексов.
С++ поддерживает многомерные массивы. Размерность массива – это число индексов, используемых для ссылки на конкретный элемент массива. Многомерные массивы должны описываться и могут при описании инициализироваться. Например: int matrix[10][20]; int m[3][3]={0, 1, 2, 10,11,12, 20,21,22}; char strings[3][80]= {“Первая строка”, “Втоая строка”, “Третья строка” }; Элементы многомерных массивов хрянятся в памяти в порядке возрастания самого правого индекса. Или, как иногда говорят, по строкам. Список начальных значений, задаваемых при описании массива, соответствует порядку элементов массива в памяти. Особый случай – инициализация двумерного массива строковыми литералами. В приведенном примере описывается двумерный массив strings, состоящий из 3-х строк по 80 символов (байт) каждая. Строки массива инициализируются символами строковых литералов. В конце каждого литерала помещается символ конца строки – ‘\0’. Многомерные массивы могут инициализироваться и без указания одной (самой левой (!)) из размерностей массива в квадратных скобках. Компилятор в этом случае определяет число элементов по числу членов в списке инициализации. Например, для массива m будет получен тот же результат, что и в предыдущем примере.
int m[][3]={0, 1, 2, 10,11,12, 20,21,22}; Имя двумерного массива является указателем-константой на массив указателей констант. Элементами массива указателей являются указатели-константы на начало каждой из строк массива. Например, для двумерного массива matrix[2][2] указателями-константами на нулевую, первую и вторую строки будут соответственно matrix[0], matrix[1] и matrix[2], а следующие выражения будут тождественными:
matrix[0] тождественно & matrix[0][0], matrix[1] тождественно & matrix[1][0], matrix[2] тождественно & matrix[2][0].
Как и для одномерных массивов, доступ к элементам двумерного массива может осуществляться по индексу или с помощью механизма указателей. Рассуждения о многомерных массивах можно эксраполировать и на большее, чем 2 число размерностей. Однако на практике массивы с большей чем 3 размерностью встречаются редко.
|
||||||||||||||||||||||||||
Последнее изменение этой страницы: 2016-04-26; просмотров: 376; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.217.10.200 (0.009 с.) |