Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

c++ / Лаб 9. Указатели и массивы

.pdf
Скачиваний:
76
Добавлен:
18.03.2015
Размер:
307.5 Кб
Скачать

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

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

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

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

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

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

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

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

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

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

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

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

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

Вариант

Размерность

Диапазон

 

 

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

 

 

массива

значений

 

 

 

 

 

 

1.

50

-100

- 100

Заменить все элементы с отрицательным

 

 

 

 

значением на значение минимального не

 

 

 

 

равного 0 положительного элемента

 

2.

200

-50

- 50

Подсчитать количество пар соседних элементов

 

 

 

 

с одинаковыми значениями

 

 

3.

200

0 - 100

Подсчитать количество участков, которые

 

 

 

 

образуют

непрерывные

последовательности

 

 

 

 

чисел с неуменьшающимися значениями

4.

200

-50

- 50

Подсчитать

количество

пар

соседних

 

 

 

 

элементов, которые имеют противоположные

 

 

 

 

знаки

 

 

 

 

 

5.

100

-100

- 100

Вывести начальные индексы всех непрерывных

 

 

 

 

последовательностей

неотрицательных чисел,

 

 

 

 

длина которых больше 5

 

 

6.

100

-100

- 100

Найти

ту

непрерывную

последовательность

 

 

 

 

положительных чисел, сумма элементов в

 

 

 

 

которой максимальная

 

 

7.

100

-100

- 100

Разместить все элементы с положительными

 

 

 

 

значениями в левой части массива, элементы с

 

 

 

 

отрицательными значениями - в правой, а нули

 

 

 

 

- между ними

 

 

 

8.

100

-100

- 100

Заменить все элементы с отрицательными

 

 

 

 

значениями

средним

арифметическим

 

 

 

 

значением всех положительных элементов

9.

200

0 - 100

Найти непрерывный участок из 10 элементов,

 

 

 

 

сумма которых максимальна

 

10.

200

0 - 100

Найти значение 3-го по величине элемента и

 

 

 

 

значения всех элементов массива, которые его

 

 

 

 

превышают, заменить на найденное значение

11.

100

-50

- 50

Найти количество пар соседних элементов,

 

 

 

 

которые

имеют

одинаковые

абсолютные

 

 

 

 

значения, но противоположные знаки

12.

200

-100

- 100

Во

всех последовательностях

положительных

 

 

 

 

чисел заменить значения элементов с

 

 

 

 

максимальным и минимальным значением на

 

 

 

 

среднее для этой последовательности

 

 

13.

200

0 - 100

Найти непрерывный участок из 10 элементов,

 

 

 

 

который имеет наибольшее среднее значение

 

 

 

 

элементов

 

 

 

 

 

 

 

14.

100

-50

- 50

Во

всех последовательностях

положительных

 

 

 

 

чисел изменить порядок элементов на

 

 

 

 

противоположный

 

 

 

 

 

15.

200

-100

- 100

Во

всех последовательностях

положительных

 

 

 

 

чисел ограничить снизу значения тех

 

 

 

 

элементов, значения которых меньше среднего

 

 

 

 

для этой последовательности

 

 

 

16.

100

-50

- 50

Заменить все элементы с положительными

 

 

 

 

значениями

 

абсолютным

 

значением

 

 

 

 

отрицательного

элемента

с

максимальным

 

 

 

 

абсолютным значением

 

 

 

 

 

17.

200

-50

- 50

Вывести начальные индексы всех непрерывных

 

 

 

 

последовательностей

 

чисел

с

не

 

 

 

 

увеличивающимися значениями

 

 

 

18.

100

-50

- 50

Вывести начальные индексы всех непрерывных

 

 

 

 

знакопеременных последовательностей чисел

19.

200

-50

- 50

Подсчитать количество всех, непрерывных

 

 

 

 

последовательностей положительных

чисел,

 

 

 

 

длина которых больше 7

 

 

 

 

 

20.

200

-50

- 50

Найти из непрерывных

 

последовательностей

 

 

 

 

отрицательных чисел ту, которая имеет

 

 

 

 

наибольшее

абсолютное

значение

среднего

 

 

 

 

арифметического ее элементов

 

 

 

21.

100

-100

- 100

Разместить все элементы с нулевыми

 

 

 

 

значениями в левой части массива, элементы с

 

 

 

 

отрицательными значениями - за ними, а за

 

 

 

 

ними - элементы с положительными

 

 

 

 

значениями

 

 

 

 

 

 

 

22.

100

-100

- 100

Ограничить

 

значения

 

всех

элементов,

 

 

 

 

абсолютные

значения

которых превышают

 

 

 

 

среднее для положительных и отрицательных

 

 

 

 

элементов

 

 

 

 

 

 

 

23.

100

-100

- 100

Заменить каждый элемент на среднее

 

 

 

 

арифметическое его и его соседей слева и

 

 

 

 

справа.

 

 

 

 

 

 

 

24.

200

-50

- 50

Найти непрерывные участки, на которых сумма

 

 

 

 

элементов равна 0

 

 

 

 

 

25.

200

-50

- 50

Для

каждого

положительного

элемента

 

 

 

 

определить, есть ли в массиве отрицательный

 

 

 

 

элемент с противоположным значением; если

 

 

 

 

да, заменить эти элементы на 0

 

 

 

26.

200

-50

- 50

Определить, какое абсолютное значение

 

 

 

 

встречается в массиве чаще остальных

 

27.

200

-50

- 50

Определить

среднюю

длину

непрерывных

 

 

 

 

участков положительных чисел

 

 

 

28.

100

-50

- 50

Поменять местами 1-й положительный элемент

 

 

 

 

с последним положительным элементом, 2-й -

 

 

 

 

предпоследним и т.д.

 

 

 

 

 

29.

100

-50

- 50

Во

всех последовательностях

отрицательных

 

 

 

чисел поменять местами элементы с

 

 

 

максимальным и минимальным значениями

30.

100

-50 - 50

Во всех последовательностях

отрицательных

 

 

 

чисел ограничить значения тех элементов,

 

 

 

абсолютное

значение которых

превышает

 

 

 

абсолютное

среднее

для

этой

 

 

 

последовательности

 

 

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

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

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

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

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

Ar[i] *(Ar+i)

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

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

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

int *Ar;

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

int size;

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

int *Cr;

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

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

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

nt av; int nn;

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

Включаем заголовочные файлы:

#include <stdio.h> #include <time.h> #include <stdlib.h>

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

Функция rand возвращает нам число в диапазоне 0 - 150, прибавлением к нему 50 мы переводим его в диапазон 50 - 200. Полученный размер массива сразу выводим на экран:

printf("size=%d\n",size);

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

Ar=(int far *)malloc(size*sizeof(int));

Функция malloc() требует параметр - размер запрошенной памяти в байтах. Переменная size - это количество элементов в массиве; для задания размера памяти в байтах умножаем ее на размер одного элемента. Функция malloc()возвращает нетипизированный указатель, мы преобразуем его в указатель на int и записываем в переменную Ar.

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

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

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

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

Тело цикла в основном подобно тому, что есть в лабораторной работе №6 за исключением того, что к текущему элементу массива мы обращаемся через указатель

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

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

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

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

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

Предпоследний оператор - обращение к функции free() для освобождения памяти, которая была выделена функцией malloc(): free(Ar);

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

#include "stdafx.h" #include <time.h> #include <windows.h> #include <stdlib.h> #include <iostream> #include <iomanip> #include <conio.h>

using namespace std;

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

{setlocale(0,"Rus");

 

int cp=GetConsoleCP();

 

int size;

// размер массива

int *Ar;

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

int *Cr, *Ir;

// текущие указатели

int av, nn;

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

srand((unsigned)time(NULL)); // инициализация ГСЧ size=rand()%151+50;

printf("size=%d\n",size); // выделения памяти

Ar=(int far *)malloc(size*sizeof(int));

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

SetConsoleCP(cp); printf("Начальный массив:\n"); for (Cr=Ar; Cr<Ar+size; Cr++) {

*Cr=rand()%101-50; printf("%3d ",*Cr);

}

putchar('\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;

// вывод результатов printf("Массив-результат:\n");

for (Cr=Ar; Cr<Ar+size; printf("%3d ",*Cr++)); putchar('\n');

// освобождение памяти free(Ar);

getch(); return 0;

}

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

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

Результаты работы программы