Автор: Пользователь скрыл имя, 17 Января 2011 в 18:57, курс лекций
6 тем.
В С++ есть четыре оператора,изменяющие естественный порядок выполнения операторов: оператор безусловного перехода goto, оператор выхода break, оператор перехода к следующей итерации цикла continue, оператор возврата из функции return.
Оператор безусловного перехода goto имеет формат:
goto <метка>;
В теле той же функции должна присутствовать ровно одна конструкция вида:
<метка>:<оператор>;
Оператор goto передает управление на помеченный меткой оператор. Рассмотрим пример использования оператора goto :
#include <iostream>
using namespace std;
int main()
{
float x;
metka:cout <<"x="; //оператор, помеченный меткой
cin>>x;
if (x) cout<<"y="<<1/x<<endl;
else
{
cout<<"функция не определена\n";
goto metka;// передача управление метке
}
return 0;
}
Следует учитывать, что
использование оператора goto з
Оператор break используется внутри операторов ветвления и цикла для обеспечения перехода в точку программы, находящуюся непосредственно за оператором, внутри которого находится break .
Мы с вами уже применяли оператор break для выхода из оператора switch, аналогичным образом он может применяться для выхода из других операторов.
Оператор перехода к следующей итерации цикла continue пропускает все операторы, оставшиеся до конца тела цикла, и передает управление на начало следующей итерации (повторение тела цикла).Рассмотрим оператор continue на примере .
#include <iostream>
using namespace std;
int main()
{
for (int i=1;i<100; ++i) // перебираем все числа от 1 до 99
{
if ( i % 2) continue ; //если число нечетное, то переходим к следующей итерации
cout << i <<"\ t "; //выводим число на экран
}
return 0;
}
В результате данной программы на экран будут выведены только четные числа из интервала от 1 до 100, т.к. для нечетных чисел текущая итерация цикла прерывалась и команда cout<<i<<"\t" не выполнялась.
Оператор возврата из функции return завершает выполнение функции и передает управление в точку ее вызова. Данный оператор мы неоднократно использовали при разработке функций, возвращающих значение
МАССИВЫ
6.1. Указатели
Когда компилятор обрабатывает
оператор определения переменной, например, int a
=50; , то он выделяет память в соответствии
с типом int и записывает в нее значение 50.
Все обращения в программе к переменной
по ее имени заменяются компилятором на
адрес области памяти, в которой хранится
значение переменной. Программист может
определить свои собственные переменные
для хранения адресов области памяти.
Такие переменные называются указателями.
В С++различают три вида указателей – указатели
на объект, на функцию и на void, которые
отличаются друг от друга свойствами и
допустимыми операциями. Указатель не
является самостоятельным типом, он всегда
связан с каким-либо другим – базовым
типом.
Указатель на объект содержит адрес области памяти, в которой хранятся данные определенного типа (простого или составного). Простейшее объявление указателя на объект имеет следующий вид:
<базовый тип> [<модификатор>] * <имя указателя>;
где базовый тип – имя типа переменной, адрес которой будет содержать переменная указатель; тип может быть любым, кроме ссылки (см. следующий раздел)и битового поля (см. справочники по С++);
модификатор необязателен и может иметь значение: near , far или huge (см. справочники по С++). По умолчанию устанавливается модификатор near. Нам этого будет достаточно для решения задач, поэтому при описании указателей модификатор явным образом указывать не будем.
Примеры:
int * a ; //указатель на целочисленное значение
int **x; //указатель на указатель на целочисленное значение
Величины типа указатель, подчиняются общим правилам определения области действия, видимости и времени жизни. Память под указатели выделяется в сегменте данных или в стеке (в зависимости от места описания и спецификатора класса памяти), а область памяти связанная с указателем обычно выделяется в динамической памяти (куче) (см. раздел 2.4).
Указатель на функцию содержит адрес в сегменте кода, по которому передается управление при вызове функции. Указатели на функцию используются для косвенного вызова функции (не через ее имя, а через переменную, хранящую ее адрес),а также для передачи функции в другую функцию в качестве параметра.
Указатель типа void применяется в тех случаях, когда конкретный тип объекта, адрес которого нужно хранить, не определен. Указателю на void можно присвоить значение указателя любого типа, а также сравнить его с любым указателем, но перед выполнением каких-либо действий с областью памяти, на которую он ссылается, требуется преобразовать его к конкретному типу явным образом.
Перед использованием любого указателя надо выполнить его инициализацию, т.е. произвести присвоение начального значения. Существуют следующие способы инициализации указателя:
1) присваивание указателю адреса существующего объекта:
· с помощью операции получения адреса:
int a =50; //целая переменная
int * x =& a ; //указателю
присваивается адрес целой
int * y (& a ); //указателю
присваивается адрес целой
· с помощью значения
другого инициализированного
int *z=x; //указателю
присваивается адрес,
· с помощью имени массива или функции (рассмотрим позже).
2) присваивание указателю адреса области памяти в явном виде:
int *p=(int *) 0xB8000000;
где 0xB8000000– шестнадцатеричная константа, ( int *) – операция явного приведения типа к типу указатель на целочисленное значение.
3) присваивание пустого значения:
int *x=NULL;
int *y=0;
где NULL стандартная константа, определенная как указатель равный 0
4) выделение участка
динамической памяти и
int *a = new int; //1
int *b = new int (50); //2
В строке 1 операция new выполняет выделение достаточного для размещения величины типа int участка динамической памяти и записывает адрес начала этого участка в переменную a . Память под переменную aвыделяется на этапе компиляции. В строке2, кроме действий описанных выше, производится инициализация выделенной динамической памяти значением 50.
Освобождение памяти, выделенной с помощью операции new, должно выполняться с помощью операции delete. При этом переменная-указатель сохраняется и может инициализироваться повторно. Пример использования операции delete:
delete a;
delete []b;
С указателями можно выполнять следующие операции: разадресации или косвенного обращения к объекту,получения адреса, присваивания, сложения с константой, вычитание, инкремент, декремент, сравнение и приведение типов.
Операция разадресации (*) предназначена для доступа к значению, адрес которой хранится в указателе. Эту операцию можно использовать как для получения значения, так и для его изменения. Рассмотрим пример:
#include <iostream>
using namespace std;
int main()
{
int *a=new int(50); //инициализация указателя на целочисленное значение
int b=*a; //переменной b присваивается значение, хранящееся по адресу указателя а
cout<<"adress \t *a\t b\n";
/*выводим: адрес, хранящийся в указателе а; значение,хранящееся по адресу
указателя а; значение переменной b*/
cout <<a<<"\t" <<*a<<"\t" <<b<<endl;
*a=100; //изменяем значение, хранящееся по адресу указателя а
cout <<a<<"\t" <<*a<<"\t" <<b<<endl;
return 0;
}
Результат работы программы:
Adress | * a | b |
00355900 | 50 | 50 |
00355900 | 100 | 50 |
Замечания
1) При запуске данной программы на вашем компьютере будет выведен другой адрес, записанный в указателе a. Это связано текущим состоянием динамической памяти.
2) При попытке выполнить команду a=100; возникнет ошибка, т.к. a – переменная-указатель, в ней может храниться только адрес ОП, но не целочисленное значение.
3) При попытке выполнить команду *b=100; также возникнет ошибка, т.к. операция разадресации может применяться только к указателям, а не к обычным переменным.
Операция получения адреса (&) применима к величинам, имеющим имя и размещенным в ОП. Рассмотрим пример :
#include<iostream>
using namespacestd;
int main()
{
int b=50;
int *a=&b; //в указатель a записали адрес переменной b
cout<<"adress \t *a\t b\n";
cout <<a <<"\t"<<*a<<"\t" <<b<<endl;
b+=10; //1
cout <<a <<"\t"<<*a<<"\t" <<b<<endl;
*a=100; //2
cout <<a <<"\t"<<*a<<"\t" <<b<<endl;
return 0;
}
Результат работы программы:
Address | *a | b |
0012FF60 | 50 | 50 |
0012FF60 | 60 | 60 |
0012FF60 | 100 | 100 |
Замечание . После того, как в указатель а был записан адрес переменной b,мы получили доступ к одной и той же области памяти через имя обычной переменной и через указатель. Поэтому, изменяя в строке1 значение переменной b, мы фактически изменяем значение по адресу, записанному в указателе а. И наоборот (см. строку 2).
Арифметические операции с указателями (сложение с константой,вычитание, инкремент и декремент) автоматически учитывают размер типа величин,адресуемых указателями. Эти операции применимы только к указателям одного типа и имеют смысл при работе со структурами данных, последовательно размещенными в памяти, например, с массивами.
Более подробно эти операции будут рассмотрены при изучении массивов. Однако хотелось обратить внимание на следующий пример:
#include <iostream>
using namespace std ;
int main()
{
int *a =new int(50);
cout <<"adress \t *a\n";
cout <<a <<"\t"<<*a<<endl;
(* a )++; // 1 увеличивается на 1 значение, хранящееся по адресу указателя а
cout <<a<<"\t" <<*a<<endl;