Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа №9_указатели и массивы+.doc
Скачиваний:
4
Добавлен:
17.11.2018
Размер:
82.43 Кб
Скачать

Лабораторная работа ╧9

Указатели и массивы

1. Цель работы

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

2. Теми для предварительной проработки

  • Указатели. Типизированные указатели.

  • Указатели и массивы.

  • Адресная арифметика.

  • Динамическое выделение памяти.

3. Задания для выполнения

     Выполнить задание лабораторной работы ╧8 с такими дополнительными условиями:

  • размер массива определяется в начале выполнения программы как случайное число в диапазоне от 10 - 200;

  • в тексте программы запрещается применять операцию индексации.

4. Варианты индивидуальных заданий

Совпадают с вариантами из лабораторной работы №8. Только память под массив выделять динамически! То есть использовать указатели и операцию new.

5. Пример решения задачи (вариант 30)

    

варианта

Размерность массива

Диапазон значений

Что нужно сделать

30

100

-50 - 50

Во всех последовательностях отрицательных чисел ограничить значения тех элементов, абсолютное значение которых превышает абсолютное среднее для этой последовательности

 Описание решения задачи приводится со ссылками на методические указания к работе ╧8. Описываются только решения, отличные от тех, что принимались в работе ╧8.

5.1. Разработка алгоритма решения.

     Алгоритм решения задачи в основном - тот же, что и в работе ╧8, поэтому его схему ми тут не приводимо. Разница состоит в том, что в начале выполнения, после инициализации датчика случайных чисел, нужно получить случайное число в диапазоне 50 - 200 (назовем его size) и выделить память для массива целых чисел размером size. (На схеме алгоритма для работы ╧8 эти действия должны быть вставлены сразу же после блока 2). Перед самым выходом из программы мы должны освободить выделенную память (На схеме алгоритма для работы ╧8 - после блока 19).

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

Ar[i] *(Ar+i)

Это соответствовало бы букве задания, но не духу языка C. Если мы переходим от индексации к адресации, у нас устраняется необходимость в индексах и даже в переменных, которые их представляют. Это приводит к другому способу реализации всех циклов. Если имя массива Ar является указателем на его начало, то вместо цикла, в котором индекс i меняется от 0 до size, мы можем организовать цикл, в котором некоторый текущий указатель Cr меняется от Ar до Ar+size. Также, когда нам нужно запомнить начало отрицательной последовательности, мы можем запоминать не индекс соответствующего элемента, а его адрес - указатель на него.

5.2. Определение переменных программы

     Переменные программы мы также описываем в сравнении с работой ╧8. Память для массива целых чисел в нашей работе не выделяется на этапе компиляции, так что нам достаточно объявить в программе только переменную - указатель на начало массива:

int *Ar;

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

int size;

     Вместо переменных, которые в работе ╧8 являются индексами элементов массива, мы будем применять указатели:

int *Cr;

это будет указатель на текущий элемент массива при его полном переборе, и:

int *Ir;

в этом указателе будет сохраняться адрес начала отрицательной последовательности, а потом - при обработке последовательности - адрес текущего ее элемента.

     Переменные для сохранения суммы элементов и среднего значения и количества элементов в последовательности остаются те же самые:

int av;

int nn;

5.3. Разработка текста программы

Включаем файлы <conio.h>, <time.h>, <stdlib.h>, <iostream>, <iomanip> и <windows.h>, позволяющие использовать генератор случайных чисел (для инициализации элементов массива), модифицированный ввод-вывод, функции установки «русской» кодировки и т.д.

     Начинаем главную функцию и объявляем в ней переменные программы по п.5.2. Кодовая часть программы начинается с инициализации датчика случайных чисел и получения случайного числа для размера массива:

srand(time(0)); /* инициализация rand */

size= rand()/1000;

     Функция rand возвращает нам число в диапазоне от нескольких десятков тысяч, деля его на 1000, мы переводим его в диапазон десятков (можно было и вычитать, даже более безопасно). Полученный размер массива сразу выводим на экран:

cout<<" size= "<< size<<endl;

     Обращаемся к функции выделения памяти:

Ar=new int [size];

и записываем результат в переменную Ar.

     Далее организуем цикл перебора массива. В отличие от работы ╧8 мы тут в одном цикле и получаем случайные числа, и выводим начальный массив на экран. Заголовок этого цикла существенно отличается от работы ╧8:

for (Cr=Ar; Cr<Ar+size; Cr++) {

     В начальных установках цикла мы записываем в переменную Cr адрес начала массива, т.е. Cr показывает на элемент с индексом 0. В конце каждой итерации Cr увеличивается на 1, т.е. показывает на следующий элемент массива. Последняя итерация происходит при значении Cr=Ar+size-1, т.е. Cr будет показывать на последний элемент. В каждой итерации мы обращаемся к текущему элементу массива как *Cr, т.е. обращаемся к тому, на что показывает указатель Cr.

     Далее идет заголовок цикла перебора массива, который организуется та же, как предыдущий, но в начальных установках мы еще присваиваемо начальное значение счетчику nn.

     Тело цикла в основном подобно тому, что есть в лабораторной работе ╧8 за исключением того, что к текущему элементу массива мы обращаемся через указатель на него: *Cr. Там, где нам требуется запомнить начало отрицательной последовательности, мы просто сохраняем текущее значение указателя Cr в переменной-указателе Ir.

     Внутренний цикл, в котором обрабатывается отрицательная последовательность, существенно отличается от работы ╧8:

for (av/=nn; Ir<Cr; Ir++)

if (*Ir<av) *Ir=av;

     Начальные установки этого цикла - только усреднение значения в av, переменная Ir уже содержит в себе указатель на первый элемент отрицательной последовательности. В конце каждой итерации Ir увеличивается на 1, т.е. показывает на следующий элемент последовательности (обращение к этому элементу - *Ir). Последняя итерация происходит при значении Ir=Cr-1, поскольку Cr показывает на первый положительный элемент за отрицательной последовательностью.

     Остаток программы повторяет предыдущие фрагменты.

     Предпоследний оператор - обращение к функции delete [] для освобождения памяти, которая была выделена функцией new.

     Полный текст программы приведен ниже.

/****************************************************/

/* Лабораторная работа ╧9 */

/* Указатели и массивы */

/* Пример выполнения. Вариант ╧30. */

/****************************************************/

#include <conio.h>

#include <time.h>

#include <stdlib.h>

#include <iostream>

#include <iomanip>

#include <windows.h>

using namespace std;

int main(void)

{

SetConsoleCP(1251);

SetConsoleOutputCP(1251);

int size; /* размер массива */

int *Ar; /* указатель на начало массива */

int *Cr, *Ir; /* текущие указатели */

int av, nn; /* среднее значение и

количество элементов в последовательности */

srand(time(0)); /* инициализация rand */

size= rand()/1000;

cout<<" size= "<< size<<endl;

getch();

/* выделения памяти */

Ar=new int [size];

/* заполнение массива случайными числами и

вывод начального массива */

cout<<"Начальный массив:"<<endl;

for (Cr=Ar; Cr<Ar+size; Cr++)

{

*Cr= rand()-5000;

cout<<setw(3)<<*Cr<<endl;

}

cout<<'\n';

/* перебор массива */

for (nn=0, Cr=Ar; Cr<Ar+size; Cr++) {

if (*Cr<0)

/* обработка отрицательного элемента */

if (!nn) {

/* начало последовательности: запомнить адрес

начала в Ir, установить начальное значение

накопителя суммы и счетчике элементов */

Ir=Cr; av=*Cr; nn=1;

}

else {

/* подсчет суммы и количества элементов */

av+=*Cr; nn++;

}

/* конец обработки отрицательного элемента */

else /* обработка положительного элемента */

if (nn) {

/* если есть необработанная отрицательная последовательность:

усреднение и перебор с ограничением */

for (av/=nn; Ir<Cr; Ir++)

if (*Ir<av) *Ir=av;

nn=0; /* последовательность обработана */

} /* конец если есть необработанная... */

} /* конец перебора массива */

if (nn) /* если не обработана последняя

отрицательная последовательность */

for (av/=nn; Ir<Cr; Ir++)

if (*Ir<av) *Ir=av;

/* вывод результатов */

cout<<"Массив-результат:\n";

for (Cr=Ar; Cr<Ar+size; cout<<setw(3)<<*Cr++<<endl);

cout<<'\n';

/* освобождение памяти */

delete [] Ar;

getch();

return 0;

}