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




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

Цель работы

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

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

  • Указатели. Типизированные указатели.
  • Указатели и массивы.
  • Адресная арифметика.
  • Динамическое выделение памяти.

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

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

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

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

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

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

 

╧ варианта Размерность массива Диапазон значений Что нужно сделать
    -50 - 50 Во всех последовательностях отрицательных чисел ограничить значения тех элементов, абсолютное значение которых превышает абсолютное среднее для этой последовательности

 

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

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

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

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

Ar[i] *(Ar+i)

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

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

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

int *Ar;

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

int size;

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

int *Cr;

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

int *Ir;

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

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

int av; int nn;

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

Включаем файлы <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;

}

Отладка программы

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



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-02-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: