Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛР15-С++24-мая-2012.doc
Скачиваний:
23
Добавлен:
23.09.2019
Размер:
1.07 Mб
Скачать

1.10. Заполнение массивов случайными числами

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

cout << "Введите значения для элементов массива:\n";

for (i=0;i<=99;i++)

{

cout << "x1[" << i << "]=";

cin >> x1[i];

}; //.

Однако при отладке программы приходится вводить с клавиатуры много элементов массива. Чтобы избавиться от этой утомительной работы целесообразно заполнять массивы случайными числами (СЧ). Для этого каждому элементу массива присваивается значение с помощью датчика псевдослучайных чисел rand().

Функция rand() определена в библиотеке stdlib и умеет генерировать псевдослучайное целое число между 0 и константой RAND_MAX, определённой в той же библиотеке. Перед использованием датчик случайных чисел необходимо инициализировать начальным значением. Для этого предназначена функция srand(unsigned long int), которая получает целый положительный аргумент и задаёт начальное число для функции rand(). Агрумент функции srand() можно вводить c клавиатуры. Тогда при вводе одинаковых значений можно получить одинаковые последовательности случайных чисел, что полезно для отладки программы. При вводе разных значений аргумента функции srand() генерируемые последовательности случайных чисел будут разными. Если вводить с клавиатуры начальное число нежелательно, то можно считывать его с системного таймера, например, так srand(time(NULL)). Функция time() принадлежит библиотеке time. Таким образом, для заполнения массива целыми числами от 0 до N можно использовать фрагмент

программы

#include<stdlib.h>

#include<time.h>

...

srand(time(NULL)); //Инициализируем датчик

for (i=0;i<=99;i++) //Для каждого элемента

x1[i]=rand()%(N+1); //Присваиваем случайное число

Здесь использована операция взятия остатка от деления для приведения диапазона значений случайной величины к отрезку [0;N]. Если необходимо заполнить массив вещественными псевдослучайными числами из отрезка [a; b], можно писать так:

x1[i]=a+(b-a)*1.0*rand()/RAND_MAX; //.

Здесь результат деления rand()/RAND_MAX по смыслу является вещественным случайным числом из отрезка [0; 1]. Однако компилятор C (C++) при делении целого на целое не выполняет приведения типа результата к вещественному числу. Поэтому в выражение введено умножение на вещественную единицу 1:0. Поскольку в правой части выражения встретился хоть один вещественный множитель, результат будет приведён к вещественному типу. Преобразование y = a + (b – a)x позволяет трансформировать диапазон значений x [0,1] в диапазон значений y [a,b].

Пример 15.2

Заполнить одномерный массив целыми случайными числами в диапазоне от -100 до 100 и определить количество положительных элементов и выдаёт сообщение на экран.

#include <iostream.h>

#include <stdlib.h>

#include <time.h>

int main(void)

{

int m[30]; //Описание массива

int i; //параметр цикла for

int n; //счётчик положительных элементов

srand(time(NULL)); //Инициализация датчика

for (i=0; i<=29;i++) //заполнение массива

m[i]=rand()%201-100; //формирование СЧ в диапазоне от -100 до 100

n=0; //обнуление счётчика элементов

for (i=0; i<=29;i++)

if (m[i]>0) //Условие положительности

n++; //Наращиваем на 1 счетчик

cout << “в массиве “ << n << “ положительных элементов”;

return 0;

} // конец программы.

Пример 15.3

Заполнить одномерный массив вещественными случайными числами в диапазоне от -0.0 до 10.0 и определить значение и индекс (номер) максимального элемента этого массива.

#include <iostream.h>

#include <stdlib.h>

#include <time.h>

int main(void)

{

float m[30]; //Описание массива

int i; //параметр цикла for

float max; //значение максимального элемента

int t; // индекс (номер) макс. элемента

srand(time(NULL)); //Инициализация датчика

for (i=0; i<=29;i++) //заполнение массива

m[i]=10.0*rand()/RAND_MAX; //формирование СЧ в диапазоне от 0 до 10.0

// допустим, что 1-й элемент максимален

max=m[0];

t=0;

for (i=1; i<=29;i++) //все остальные элементы

if (m[i]>max) //сравниваем с максимальным

{

max=m[i];

t=i;

};

cout << "максимальный элемент = " << max;

cout << "номер максимального элемента " << t;

return 0;

} // конец программы.

Пример 15.4

Задан двумерный массив b[10][10] целых чисел, заполненный случайными числами из отрезка [-10,10]. Найти и вывести на экран те элементы массива, которые больше заданного числа k.

#include <iostream.h>

#include <math.h>

#include <stdlib.h>

#include <time.h>

int main(void)

{

int b[10][10];

int i, j, k;

srand(time(NULL)); //Инициализация датчика

for (i=0; i<=9; i++) //заполнение массива

{

for (j=0; j<=9; j++)

{

b [i][j]=rand()%21-10; //формирование СЧ в диапазоне от -10 до 10

cout << b[i][j] << " ";

};

cout << endl;

};

cout << "Введите число k";

cin >> k;

for (i=0; i<=9; i++)

for (j=0; j<=9; j++)

if (b[i][j]>k) cout << b[i][j] << "\t";

cout << endl;

} //.

1.11. Ссылки в С++

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

// структура объявления ссылок

/*тип*/ &/*имя ссылки*/ = /*имя переменной*/;

При объявлении ссылки перед её именем ставится символ амперсанда "&", сама же ссылка должна быть проинициализирована именем переменной, на которую она ссылается. Тип данных, на который указывает ссылка, может быть любым, но должен совпадать с объектом, на который ссылается, то есть с типом данных ссылочной переменной. Для удобства, будем называть  переменную, на которую ссылается ссылка  "ссылочной переменной". Любое изменение значения содержащегося в ссылке повлечёт за собой изменение этого значения в переменной, на которую ссылается ссылка. Разработаем программу, в которой объявим ссылку на объект типа int.

// №1.cpp: определяет точку входа для консольного приложения.

  

#include "stdafx.h"

#include <iostream>

using namespace std;

  

int main(int argc, char* argv[])

{

    int value = 15;

    int &reference = value; // объявление и инициализация ссылки значением переменной value

    cout << "value     = " << value     << endl;

    cout << "reference = " << reference << endl;

    reference+=15; // изменяем значение переменной value посредством изменения значения в ссылке

    cout << "value     = " << value     << endl; // смотрим, что получилось, как будет видно дальше значение поменялось как в ссылке,

    cout << "reference = " << reference << endl; //  так и в ссылочной переменной

    system("pause");

    return 0;

}

В строке 10 объявлена ссылка reference типа int  на переменную value. В строке 13 суммируется значение переменной value с числом 15, черезссылку reference. Результат работы программы (рис. 15.1).

Рис. 15.1.Ссылки в С++

Просмотрев результат работы программы можно сказать, что через ссылку меняется значение ссылочной переменной. Таким образом, сама ссылка не имеет как таковой копии значения взятой у переменной при инициализации ссылки, а всего лишь ссылка ссылается на ссылочную переменную посредством её адреса.

Ссылки, как правило, в большинстве случаев используют в функциях как ссылки-параметры или ссылки-аргументы.  Напомню, что в языке программирования С++ в функции передаются данные по значению и по ссылке. Так вот, когда происходит передача по значению, те данные, которые необходимо передать, нужно сначала скопировать, а когда передаётся большой объём данных, то только на передачу затрачивается большое количество времени и ресурсов. В таком случае необходимо использовать передачу по ссылке, в этом случае данные копировать нет необходимости, так как к ним обеспечен прямой доступ, но нарушают безопасность данных, хранимых в ссылочных переменных, так как открывают прямой доступ к этим данным. Хотя далее мы рассмотрим, как обеспечить целостность данных и скорость их передачи. Для этого, разработаем программу, в которой создадим три функции, аргументы в которых будут передаваться по значению и по ссылке. Вдобавок ко всему этому  ещё и передачу через указатель осуществим. Частенько возникает путаница между указателями и ссылками, на первый взгляд и ссылки и указатели работают одинаково, но разница все, же есть и весьма значительная.

// reference.cpp: определяет точку входа для консольного приложения.

  #include "stdafx.h"

#include <iostream>

using namespace std;

  int sum_by_value(int );// суммирование по значению

int sum_by_reference(int &);// суммирование по ссылке

int sum_by_pointer(int *); // суммирование по указателю

  int _tmain(int argc, _TCHAR* argv[])

{

    int value = 10;

    cout << "sum_by_value     = " << sum_by_value(value)     << endl;

    cout << "value = " << value   << endl; // значение переменной осталось неизменным

    cout << "sum_by_reference = " << sum_by_reference(value) << endl;

    cout << "value = " << value   << endl; // значение переменной изменилось

    cout << "sum_by_pointer     = " << sum_by_pointer(&value)  << endl;

    cout << "value = " << value   << endl; // значение переменной изменилось ещё раз

    system("pause");

    return 0;

}

  int sum_by_value(int value)// функция принимающая аргумент по значению

{

    value += value;

    return value;

}

  int sum_by_reference(int &reference) // функция принимающая аргумент по ссылке

{

    reference += reference;

    return reference;

}

  int sum_by_pointer(int *ptrvalue)// функция принимающая аргумент через указатель

{

    *ptrvalue += *ptrvalue;// арифметика с указателем

    return *ptrvalue;

}

Начальное значение осталось неизменным в случае передачи по значению, тогда как передача по ссылке и через указатель изменили значение передаваемой переменной. Таким образом, нет необходимости использовать глобальные переменные при необходимости изменения значения передаваемой переменной, нужно воспользоваться ссылкой или указателем. В случае использования указателя строка 16 нельзя забывать про операцию взятия адреса, так как аргументом является указатель. В случае со ссылкой, достаточно указать только имя переменной и всё строка 14. Результат работы программы (рис. 15.2).

Рис. 15.2. Ссылки в С++

В чём же разница между указателями  и ссылками? Основное назначение указателя – это организация динамических объектов, то есть размер, которых может меняться (увеличиваться или уменьшаться). Тогда как ссылки предназначены для организации прямого доступа к тому, или иному объекту. Главное отличие состоит во внутреннем механизме работы. Указатели ссылаются на участок в памяти, используя его адрес. А ссылки ссылаются на объект, по его имени (тоже своего рода адрес). Если нет необходимости изменить передаваемое значение в ссылочной переменной, но нужно выиграть в скорости, используйте спецификатор const в объявлении параметров функций. Только так и можно защитить данные от случайного их изменения или полной потере.

int sum_by_reference(const int &reference) // функция принимающая аргумент по ссылке 

// квалификатор const не даёт изменить передаваемый аргумент внутри функции