Программирование вложенных циклов
Тело цикла может содержать любые операторы, в том числе и другие циклы. Оператор цикла, который содержится в теле другого цикла, называется вложенным.
Задача №7: Напечатать N простых чисел.
Разделим эту задачу на две подзадачи:
1. определить является ли число простым;
2. напечатать n чисел, удовлетворяющих заданному условию.
Простым называется число, которое делится только само на себя и на единицу (сама единица простым числом не является). Тогда, чтобы определить является число простым или нет, нужно проверить есть ли у него другие делители. Для этого будем делить число К на все числа от 2 и до К, используя цикл с постусловием. Если К разделится на d без остатка только, когда d станет равно К, значит, число простое:
d=1;//начальное значение делителя
do
{
d++;//увеличиваем делитель
}
/*цикл выполняется пока остаток от деления К на d не равен 0 (не делится)*/
while(К%d!=0);
if(К==d)//делитель равен К, т. е. число простое
cout<<a<<" ";
Для решения второй подзадачи, нам нужно перебирать все числа, начиная с 2, и печатать только те, которые являются простыми. При этом, нужно подсчитывать напечатанные числа. Выполнение цикла закончится, когда будет напечатано n чисел.
K=1;//присваиваем начальное значение числу
//выполняем цикл пока не будет напечатано n чисел
for(int i=0;i<n;)
{
K++;//берем следующее число
if (K простое число)
i++;//увеличиваем счетчик простых чисел
|
|
}
Объединив эти два фрагмента вместе, получим решение поставленной задачи
#include<iostream.h>
void main()
{
int K=1,n,d;
cout<<"\nEnter N";
cin>>n;
//неправильно задано число n
if(n<1) {
cout<<”\nerror in data”;
return;//завершение программы
}
for(int i=0;i<n;)//внешний цикл
{
K++;d=1;
do //внутренний цикл
{
d++;
}
while(K%d!=0);//конец внутреннего цикла
if(K==d){
cout<<K<<" ";
i++;}
}//конец внешнего цикла
}
Тесты
n=0 | Error in data |
n=1 | 2 |
n=5 | 10 |
Массивы
В языке C/C++, кроме базовых типов, разрешено вводить и использовать производные типы, полученные на основе базовых. Стандарт языка определяет три способа получения производных типов:
· массив элементов заданного типа;
· указатель на объект заданного типа;
· функция, возвращающая значение заданного типа.
Массив – это упорядоченная последовательность переменных одного типа. Каждому элементу массива отводится одна ячейка памяти. Элементы одного массива занимают последовательно расположенные ячейки памяти. Все элементы имеют одно имя – имя массива и отличаются индексами – порядковыми номерами в массиве. Количество элементов в массиве называется его размером. Чтобы отвести в памяти нужное количество ячеек для размещения массива, надо заранее знать его размер. Резервирование памяти для массива выполняется на этапе компиляции программы.
|
|
12.1. Определение массива в C/C++
Массивы определяются следующим образом:
int a[100];//массив из 100 элементов целого типа
Операция sizeof(a) даст результат 400, т. е. 100 элементов по 4 байта.
Элементы массива всегда нумеруются с 0.
45 | 352 | 63 | 124 | значения элементов массива | |
0 | 1 | 2 | ….. | 99 | индексы элементов массива |
Рис. 4. Размещение массива в памяти
Чтобы обратиться к элементу массива, надо указать имя массива и номер элемента в массиве (индекс):
a[0] – индекс задается как константа,
a[55] – индекс задается как константа,
a[i] – индекс задается как переменная,
a[2*i] – индекс задается как выражение.
Элементы массива можно задавать при его определении:
int a[10]={1,2,3,4,5,6,7,8,9,10};
Операция sizeof(a) даст результат 40, т. е. 10 элементов по 4 байта.
int a[10]={1,2,3,4,5};
Операция sizeof(a) даст результат 40, т. е. 10 элементов по 4 байта. Если количество начальных значений меньше, чем объявленная длина массива, то начальные элементы массива получат только первые элементы.
int a[]={1,2,3,4,5};
|
|
Операция sizeof(a) даст результат 20, т. е. 5 элементов по 4 байта. Длина массива вычисляется компилятором по количеству значений, перечисленных при инициализации.
Примеры решения задач и использованием массивов
Задача 1. Формирование массива с помощью датчика случайных чисел.
Для того чтобы сформировать массив необходимо организовать цикл для перебора элементов массива. Для формирования каждого элемента вызывается функция rand(),которая возвращает псевдослучайное число из диапазона от 0 до 32767. Чтобы получить значения из диапазона от 0 до 100 используется операция получения остатка от деления %. Если нужно получить не только положительные, но и отрицательные числа вычитается число k равное половине от требуемого диапазона.
a[I]=rand()%100-50;//числа из диапазона -50..49.
Чтобы использовать функцию rand(), надо подключить библиотечный файл <stdlib.h>
#include <iostream.h>
#include <stdlib.h> //файл с описанием функции rand()
void main()
{
int a[100];
int n;
cout<<”\nEnter the size of array:”;cin>>n;
for(int I=0;I<n;I++)
{
a[I]=rand()%100;// числа из диапазона 0..100
cout<<a[I]<<” ”; //вывод элемента массива
}
}
Задача 3. Найти максимальный элемент массива.
Для решения этой задачи нужно сформировать массив, присвоить начальное значение в переменную max, в качестве начального значения выступает первый элемент массива, а затем сравнить каждый элемент массива с переменной max. Если значение элемента будет больше max, то его значение записывается в max и последующие элементы сравниваются уже с этим значением.
|
|
#include <iostream.h>
#include <stdlib.h>
void main()
{
int a[100];
int n;
cout<<”\nEnter the size of array:”;
cin>>n;
for(int I=0;I<n;I++) //заполнение массива
{
a[I]=rand()%100-50;
cout<<a[I]<<” ”;
}
int max=a[0]; //задаем начальное значение max
for(I=1;I<n;I++)
//сравниваем элементы массива с max
if(a[I]>max)max=a[I];
cout<<”\nMax=”<<max;
}
Задача 3. Найти сумму элементов массива с четными индексами.
Для решения этой задачи можно предложить несколько способов.
- Массив перебирается с шагом 2 и все элементы суммируются.
- Массив перебирается с шагом 1 и суммируются только элементы, имеющие четные индексы. Для проверки на четность используется операция получения остатка от деления на 2.
//Первый способ
#include <iostream.h>
#include <stdlib.h>
void main()
{
int a[100];
int n;
cout<<”\nEnter the size of array:”;
cin>>n;
for(int I=0;I<n;I++)
{
//заполнение массива случайными числами
a[I]=rand()%100-50;
cout<<a[I]<<” ”;
}
int Sum=0;
for(I=0; I<n; I+=2)
//суммируются элементы с индексами 0, 2, 4, и т. д.
Sum+=a[I];
cout<<”\nSum=”<<Sum”;
}
//Второй способ
#include <iostream.h>
#include <stdlib.h>
void main()
{
int a[100];
int n;
cout<<”\nEnter the size of array:”;
cin>>n;
for(int I=0;I<n;I++)
{
//заполнение массива случайными числами
a[I]=rand()%100-50;
cout<<a[I]<<” ”;
}
int Sum=0;
for(I=0; I<n; I++)
if(I%2==0)
//суммируются элементы с индексами 0, 2, 4, и т. д.
Sum+=a[I];
cout<<”\nSum=”<<Sum”;
}
Указатели
Понятие указателя
Указатели являются специальными объектами в программах на C/C++. Указатели предназначены для хранения адресов памяти.
Когда компилятор обрабатывает оператор определения переменной, например, int i=10;, то в памяти выделяется участок памяти в соответствии с типом переменной (для int размер участка памяти составит 4 байта) и записывает в этот участок указанное значение. Все обращения к этой переменной компилятор заменит адресом области памяти, в которой хранится эта переменная.
Рис. 5 Значение переменной и ее адрес
Программист может определить собственные переменные для хранения адресов областей памяти. Такие переменные называются указателями. Указатель не является самостоятельным типом, он всегда связан с каким-то другим типом.
Указатели делятся на две категории: указатели на объекты и указатели на функции. Рассмотрим указатели на объекты, которые хранят адрес области памяти, содержащей данные определенного типа.
В простейшем случае объявление указателя имеет вид:
тип* имя;
Знак *, обозначает указатель и относится к типу переменной, поэтому его рекомендуется ставить рядом с типом, а от имени переменной отделять пробелом, за исключением тех случаев, когда описываются несколько указателей. При описании нескольких указателей знак * ставится перед именем переменной-указателя, т. к. иначе будет не понятно, что эта переменная также является указателем.
int* i;
double *f, *ff;//два указателя
char* c;
Тип может быть любым, кроме ссылки.
Размер указателя зависит от модели памяти. Можно определить указатель на указатель: int** a;
Указатель может быть константой или переменной, а также указывать на константу или переменную.
int i; //целая переменная
const int ci=1; //целая константа
int* pi; //указатель на целую переменную
const int* pci; //указатель на целую константу
Указатель можно сразу проинициализировать:
//указатель на целую переменную
int* pi=&i;
//указатель на целую константу
const int* pci=&ci;
//указатель-константа на переменную целого типа
int* const cpi=&i;
//указатель-константа на целую константу
const int* const cpc=&ci;
Если модификатор const относится к указателю (т. е. находится между именем указателя и *), то он запрещает изменение указателя, а если он находится слева от типа (т. е. слева от *), то он запрещает изменение значения, на которое указывает указатель.
Для инициализации указателя существуют следующие способы:
· с помощью операции получения адреса
int a=5;
int* p=&a; или int p(&a);
· с помощью проинициализированного указателя
int* r=p;
· адрес присваивается в явном виде
char* cp=(char*)0х В800 0000;
где 0х В800 0000 – шестнадцатеричная константа,
(char*) – операция приведения типа.
· присваивание пустого значения:
int* N=NULL;
int* R=0;
Динамическая память
Все переменные, объявленные в программе размещаются в одной непрерывной области памяти, которую называют сегментом данных (64 Кб). Такие переменные не меняют своего размера в ходе выполнения программы и называются статическими. Размера сегмента данных может быть недостаточно для размещения больших массивов информации. Выходом из этой ситуации является использование динамической памяти. Динамическая память – это память, выделяемая программе для ее работы за вычетом сегмента данных, стека, в котором размещаются локальные переменные подпрограмм и собственно тела программы.
Для работы с динамической памятью используют указатели. С их помощью осуществляется доступ к участкам динамической памяти, которые называются динамическими переменными. Динамические переменные создаются с помощью специальных функций и операций. Они существуют либо до конца работы программ, либо до тех пор, пока не будут уничтожены с помощью специальных функций или операций.
Для создания динамических переменных используют операцию new, определенную в C++:
указатель = new имя_типа[инициализатор];
где инициализатор – выражение в круглых скобках.
Операция new позволяет выделить и сделать доступным участок динамической памяти, который соответствует заданному типу данных. Если задан инициализатор, то в этот участок будет занесено значение, указанное в инициализаторе.
int* x=new int(5);
Для удаления динамических переменных используется операция delete, определенная в C++:
delete указатель;
где указатель содержит адрес участка памяти, ранее выделенный с помощью операции new.
delete x;
Операции с указателями
С указателями можно выполнять следующие операции:
· разыменование (*);
· присваивание;
· арифметические операции (сложение с константой, вычитание,
инкремент ++, декремент --);
· сравнение;
· приведение типов.
Операция разыменования предназначена для получения значения переменной или константы, адрес которой хранится в указателе. Если указатель указывает на переменную, то это значение можно изменять, также используя операцию разыменования.
int a; //переменная типа int
int* pa=new int; //указатель и выделение памяти под //динамическую переменную
*pa=10;//присвоили значение динамической
//переменной, на которую указывает указатель
a=*pa;//присвоили значение переменной а
Присваивать значение указателям-константам запрещено.
Приведение типов. На одну и ту же область памяти могут ссылаться указатели разного типа. Если применить к ним операцию разыменования, то получатся разные результаты.
int a=123;
int* pi=&a;
char* pc=(char*)&a;
float* pf=(float*)&a;
printf("\n%x\t%i",pi,*pi);
printf("\n%x\t%c",pc,*pc);
printf("\n%x\t%f",pf,*pf);
При выполнении этой программы получатся следующие результаты:
66fd9c 123
66fd9c {
66fd9c 0.000000
Т. е. адрес у трех указателей один и тот же, но при разыменовании получаются разные значения в зависимости от типа указателя.
В примере при инициализации указателя была использована операция приведения типов. При использовании в выражении указателей разных типов, явное преобразование требуется для всех типов, кроме void*. Указатель может неявно преобразовываться в значения типа bool, при этом ненулевой указатель преобразуется в true, а нулевой в false.
Арифметические операции применимы только к указателям одного типа.
· Инкремент увеличивает значение указателя на величину sizeof(тип).
char* pc;
int* pi;
double* pd;
. . . . .
pc++; //значение увеличится на 1
pi++; //значение увеличится на 4
pd++; //значение увеличится на 8
· Декремент уменьшает значение указателя на величину sizeof(тип).
· Разность двух указателей – это разность их значений, деленная на размер типа в байтах.
int a=123, b=456, c=789;
int* pi1=&a;
int* pi2=&b;
int* pi3=&c;
printf("\n%x",pi1-pi2);
printf("\n%x",pi1-pi3);
Результат выполнения программы:
1
2
Суммирование двух указателей не допускается.
· Можно суммировать указатель и константу:
pi3=pi3+2;
pi2=pi2+1;
printf("\n%x\t%d",pi1,*pi1);
printf("\n%x\t%d",pi2,*pi2);
printf("\n%x\t%d",pi3,*pi3);
Результат выполнения программы:
66fd9c 123
66fd9c 123
66fd9c 123
Ссылки
Ссылка – это синоним имени объекта, указанного при инициализации ссылки.
Формат объявления ссылки
тип & имя =имя_объекта;
int x; // определение переменной
int& sx=x; // определение ссылки на переменную х
const char& CR=’\n’; //определение ссылки на константу
Правила работы со ссылками:
· Переменная-ссылка должна явно инициализироваться при ее описании, если она не является параметром функции, не описана как extern или не ссылается на поле класса.
· После инициализации ссылке не может быть присвоено другое значение.
· Не существует указателей на ссылки, массивов ссылок и ссылок на ссылки.
· Операция над ссылкой приводит к изменению величины, на которую она ссылается.
Ссылка не занимает дополнительного пространства в памяти, она является просто другим именем объекта.
#include<iostream.h>
void main()
{
int i=123;
int& si=i;
cout<<”\ni=”<<i<<” si=”<<si;
i=456;
cout<<”\ni=”<<i<<” si=”<<si;
i=0;
cout<<”\ni=”<<i<<” si=”<<si;
}
Выведется:
i=123 si=123
i=456 si=456
i=0 si=0
Указатели и массивы
Дата добавления: 2018-04-04; просмотров: 472; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!