
Int a[15]; // массив из 15 целочисленных элементов с именем a
float x[3]; // массив x из 3-х элементов типа float
Объявление массива является командой компилятору на выделение памяти для хранения его элементов. Общее количество выделенной памяти зависит не только от числа элементов, но и от размера каждого элемента, то есть от его типа. Например, текстовая строка из 1000 символов (тип char) займет P = 1000*sizeof(char) = 1000 байтов, а массив из такого же количества вещественных чисел двойной точности (тип double) займет уже в восемь раз больше – P = 1000*sizeof(double) = 8000 байтов.
Нумерация элементов в массиве начинается с нуля. Таким образом, первый элемент массива имеет индекс 0, а последний – индекс n-1, где n – размер массива. Обращение к элементу производится с использованием имени массива и индекса элемента в квадратных скобках. Например, запись “x[0] = 5.5;” означает “присвоить значение 5.5 нулевому элементу массива x”.
Для работы с массивами характерным является использование итерационных циклов for. С их помощью организуется выполнение однотипных операций со всеми элементами массива, в частности, поэлементный ввод-вывод, поэлементные арифметические операции и др.
Задание
1. Изучить: способы описания размеров массивов на языке программирования; способы ввода и вывода массивов; реализацию на конкретном языке программирования приемов накопления суммы или произведения, запоминания результатов, нахождения наибольшего и наименьшего.
2. Разработать алгоритм решения в соответствии с заданием.
3. Составить программу решения задачи.
4. Подготовить тест для проверки программы.
Пример выполнения работы
Условие: Напишите программу, запрашивающую у пользователя 10 целых чисел, и выводящую на экран их сумму.
#include <conio.h>
#include <iostream.h>
void main(void)
{
int A[10]; // объявляем массив из 10 целых
for(int i=0; i<10; i++) // организуем цикл по i от 0 до 9
{
cout << "input A[" << i << "] = "; // приглашение
cin >> A[i]; // вводим A[i]
}
int sum = 0; // объявляем переменную
for(int i=0; i<10; i++) // организуем цикл
sum = sum + A[i]; // в цикле суммируем элементы
cout << "\nSumma: " << sum; // выводим результат на экран
getch(); // задержка
}
Условие: Дан одномерный массив x[n], где n – размер массива. Найти k–й отрицательный элемент массива.
Начальные данные:
1. константа n, которая определяет размер массива;
2. одномерный массив размерности n;
3. параметр k для порядкового номера отрицательного элемента массива;
4. параметр kn для подсчета числа отрицательных элементов массива;
5. параметр ki для индекса найденного элемента массива.
Результат вычисления: значения параметра kn; значения параметра ki.
#include<iostream.h>
#include<conio.h>
#include<stdlib.h>
void main(void)
{ const n = 10;
int i, a[n] ;
int k, kn = 0, ki = -1; // kn – для числа отрицательных элементов.
// ki – для индекса текущего отрицательного элемента.
// k – для порядкового номера отрицательного элемента массива.
clrscr();
// Ввод одномерного массива с клавиатуры.
cout << "Введи элементы массива с клавиатуры: \n";
for ( i = 0; i <= n-1; i++ ) // Начало цикла. Перебор индексов массива.
{
printf("a[ %d ]= ", i); // Подсказка для пользователя.
scanf( "%d", &a[i] ); // Ввод элемента массива с клавиатуры.
}
// Вывод массива на терминал.
clrscr();
cout << "Введен массив: \n";
for ( i = 0; i <= n-1; i++ )
printf("%d ", a[i]);
cout << "\n";
cout << "Введи номер для поиска отрицательного элемента k= ";
cin >> k;
// Начало подсчета числа отрицательных элементов в массиве.
for ( i = 0; i <= n-1; i++ )
{
if (a[i] < 0 )
{
kn++; // Если элемент массива отрицательный, значение kn
// увеличиваем на 1.
ki = i; // Запоминаем индекс текущего отрицательного элемента.
if ( kn == k )break; // Нашли отрицательный элемент с заданным
// порядковым номером.
}
}
if ( kn == k )
cout << "Элемент a(" << ki << ")= " << a[ki] << " является " << kn << "- ым отрицательным элементом массива \n";
else
cout << "Отрицательных элементов с порядковым номером " << k << " отсутствует\n";
getch(); }
Задания для самостоятельного выполнения
Задан одномерный числовой массив. Вычислить среднее арифметическое тех его элементов, значения которых лежат в интервале от 0 до 9.
Задан одномерный числовой массив. Заменить все его максимальные элементы числом 100.
Задан одномерный числовой массив, в котором есть хотя бы один отрицательный элемент. Определить количество элементов, расположенных до первого отрицательного элемента.
Задан одномерный числовой массив. Верно ли, что количество его положительных элементов не превышает количества его отрицательных элементов?
Задан одномерный числовой массив. Заменить последний из его минимальных элементов значением последнего элемента всего массива.
Задан одномерный числовой массив, в котором есть хотя бы один нулевой элемент. Какое количество элементов расположено после первого нулевого элемента до конца массива?
Задан одномерный числовой массив. Вычислить количество тех его элементов, значения которых совпадают с последним элементом этого массива.
Задан одномерный числовой массив. Вычислить сумму тех его элементов, значения которых отличны от значения максимального элемента этого массива.
Задан одномерный числовой массив, в котором есть хотя бы один отрицательный элемент. Поменять местами значения первого элемента этого массива и первого встретившегося отрицательного элемента.
Задан одномерный числовой массив. Вычислить сумму тех его элементов, значения которых есть четные числа.
Задан одномерный числовой массив. Подсчитать количество максимальных элементов этого массива.
Найти сумму всех элементов массива, имеющих четные индексы.
Дан массив А, содержащий положительные, отрицательные и нулевые элементы. Из индексов нулевых элементов сформировать новый массив С и найти произведение его элементов.
Определить, сколько элементов массива больше, чем число 3 и меньше, чем число -1.
Найти сумму элементов массива, превышающих число 8.
Найти произведение отрицательных элементов массива.
В массиве определить индексы нулевых элементов и заменить нулевые элементы на 5.
Дан массив А, содержащий положительные, отрицательные и нулевые элементы. Из отрицательных элементов массива, сформировать новый массив С и найти среднее геометрическое его элементов.
Найти разность между наибольшим и наименьшим элементами массива.
Контрольные вопросы
1. Указать особенности программ, использующих массивы.
2. Какие операторы языка можно использовать для описания массивов?
3. В чем состоит особенность организации цикла при обработке массивов?
4. В чем состоит особенность использования приемов программирования при обработке массивов?
5. Указать особенности ввода и вывода массивов.
6. Что представляет собой одномерный массив?
7. Индекс первого элемента массива всегда равен нулю. Верно ли это?
8. Предусмотрена ли в С++ проверка «нерушимости» границ массива?
9. Каждая размерность многомерного массива в С++ заключается в собственную пару квадратных скобок. Верно ли это?
10. Покажите, как объявить двумерный целочисленный массив с именем mas размерностью 10 х 8?
11. Может ли содержать массив переменные нескольких типов?
Лабораторная работа № 5. Составление программ обработки двумерных массивов
Цель работы: овладеть навыками алгоритмизации и программирования структур с вложенными циклами, особенностями обработки двумерных массивов, способами их ввода и вывода.
Краткие теоретические сведения
Массивы в программах C++ могут быть не только линейными. Довольно частым является использование двух - (и более) -мерных структур. К примеру, прямоугольная матрица – типичная структура, представимая с помощью двумерного массива.
Многомерный массив в C++ организован по принципу «массива массивов» (рис. 6). Общий формат его объявления:
тип имя[N1][N2]…[NM];
Рис. 6. Пример двумерного массива
Здесь M – число индексов (или размерность) массива. Индексы изменяются в пределах от 0 до N1 – 1, от 0 до N2 – 1, от 0 до N3 – 1, ..., от 0 до NM – 1, соответственно.
К примеру, запись int G[5][4]; означает объявление двумерного массива целых чисел с именем G и размерами 54. Доступ к элементам многомерного массива в программе производится так же, как и в одномерном случае, то есть путем указания имени массива и набора индексов в квадратных скобках. Например, операция присваивания значения 0 последнему элементу будет записана как G[4][3] = 0.
При работе с многомерными массивами удобно использовать вложенные циклы for. С их помощью можно выполнить заданное действие с каждым из элементов массива путем перебора всех значений индексов. Приведенный ниже фрагмент программного кода выводит на экран все элементы массива G.
for(int i=0; i<5; i++) // цикл по строкам i
{
for(int j=0; j<4; j++) // цикл по строкам j
cout << G[i][j] << “\t”; // выводим G[i][j]
cout << endl; // перевод на новую строку
}
Алгоритм
работы этого фрагмента иллюстрируется
следующей блок-схемой (рис. 7).
Рис. 7. Блок – схема вывода элементов массива на экран
Здесь внешний цикл по I последовательно пробегает все значения от 0 до 5. При каждом i запускается внутренний цикл по j от 0 до 4. В теле этого цикла на экран выводятся значение элемента G[i][j] и знак табуляции (горизонтальный отступ). Внутренний цикл продолжается до тех пор, пока не будут перебраны все значения j, то есть не будет выведена вся i-я строка. По завершении внутреннего цикла, экранный курсор перемещается на новую строку манипулятором endl, и далее внешний цикл продолжает свою работу, последовательно выводя на экран другие строки массива.
Задание
1. Изучить: правила организации вложенного цикла с учетом порядка перебо-
ра элементов матрицы; правила использования приемов программирования в структурах с вложенными циклами; способы ввода и вывода матриц, имеющиеся в языке программирования.
2. Разработать алгоритм решения в соответствии с заданием.
3. Составить программу решения задачи.
Пример выполнения работы
Условие: Имеется вещественная квадратная матрица размером 44. Напишите программу, вычисляющую произведение элементов в каждой ее строке. Матрица вводится с клавиатуры.
#include <conio.h>
#include <iostream.h>
void main(void)
{
float X[4][4]; // объявляем массив 44
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
{
cout << "input X[" << i << "," << j << "] = ";
cin >> X[i][j]; // вводим элементы матрицы
}
cout << "\n Results:\n";
for(int i=0; i<4; i++) // цикл по строкам
{
float P = 1.0; // вспомогательная переменная
for(int j=0; j<4; j++) // цикл по элементам в строке
P = P * X[i][j]; // домножаем P на X[i][j]
cout << "\n proizvedenie " << i << "-i stroki = " << P; // выводим результат на экран
}
getch(); }
Условие: Дана квадратная матрица размером N x N. Переставить элементы верхнего треугольника матрицы с соответствующими элементами нижнего треугольника.
Начальные данные:
1. константа n, которая определяет размер матрицы;
2. двумерный массив размерности n;
3. параметр i для цикла по строкам;
4. параметр j для цикла по столбцам;
5. параметр r для промежуточной информации.
Результат вычисления: новая матрица с переставленными элементами.
#include<stdio.h>
#include<conio.h>
#include<iostream.h>
void main(void)
{ const n = 2;
int i,j, a[n][n];
int r;
clrscr();
printf (" Введи элементы матрицы: \n");
for (i = 0; i <= n-1;i++)
for ( j = 0; j <= n-1; j++)
{ printf("a(%d,%d)= ",i,j);
scanf( "%d", &a[i][j]);
}
cout << "Введена матрица: \n";
for ( i = 0;i < n; i++)
{ for ( i = 0; j < n; j++)
printf("%d ", a[i][j]);
printf("\n");
}
for ( i = 0; i <= n/2; i++)
for (j = i; j <= n-1-i; j++)
{ r = a[i][j];
a[i][j] = a[n-1-i][j];
a[n-1-i] [j]=r;
}
cout << "\n\nМатрица после перестановки:\n";
for ( i = 0; i <= n-1; i++)
{ for ( j = 0; j <= n-1; j++)
printf("%d ", a[i][j]);
printf("\n");
}
getch();
}
Условие:
Пусть
и
– две квадратные матрицы размером 33.
Требуется написать программу,
рассчитывающую их произведение
Искомое
произведение
– это также матрица 33,
элементы которой рассчитываются по
формуле
(
).
#include <conio.h>
#include <iostream.h>
const int N = 3; // используем константу N=3
void main(void)
{ float A[N][N] = { {1, 1, 1},
{2, 2, 2},
{3, 3, 3} }; // исходная матрица A
float B[N][N] = { {1, 2, 3},
{1, 2, 3},
{1, 2, 3} }; // исходная матрица B
float C[N][N]; // матрица произведения С
for(int i=0; i<N; i++) // цикл по строкам С
{
for(int j=0; j<N; j++) // цикл по столбцам С
{
float s = 0.0; // вспомогательная переменная
for(int k=0; k<N; k++) // цикл суммирования по k
s += A[i][k]*B[k][j]; // добавляем к s новое слаг-ое
C[i][j] = s; // записываем s в C[i][j]
}
}
cout << " Results: \n"; // далее выводим C на экран
for(int i=0; i<N; i++)
{
for(int j=0; j<N; j++)
cout << C[i][j] << "\t";
cout << endl;
}
getch();
}
Задания для самостоятельного выполнения
Для заданного двумерного числового массива подсчитать количество строк, состоящих только из ненулевых элементов.
Для заданного двумерного числового массива подсчитать количество столбцов, состоящих только из отрицательных элементов.
Для заданного двумерного числового массива подсчитать количество таких строк, в которых положительных элементов больше, чем отрицательных.
Для заданного двумерного числового массива подсчитать количество таких столбцов, у которых максимальный элемент этого столбца расположен в первой строке.
Для заданного двумерного числового массива подсчитать количество таких столбцов, у которых максимальный элемент этого столбца единственный.
Для заданного двумерного числового массива подсчитать количество таких столбцов, у которых максимальный элемент этого столбца расположен в первой строке.
Дана целочисленная матрица размера M x N. Найти количество ее строк столбцов, все элементы которых различны.
Дана квадратная матрица. Найти максимальное значение из элементов, расположенных в левом нижнем углу.
Дана квадратная матрица порядка M. Найти суммы элементов ее диагоналей, параллельных главной побочной (начиная с одноэлементной диагонали A[1,M]1|A[1,1]2).
Дана квадратная матрица порядка M. Заменить нулями элементы, лежащие одновременно выше ниже главной диагонали (включая эту диагональ) и выше ниже побочной диагонали (также включая эту диагональ).
Дана квадратная матрица порядка M. Зеркально отразить ее элементы относительно [горизонтальной оси симметрии] [вертикальной оси симметрии] [главной диагонали] [побочной диагонали] матрицы.
Дана квадратная матрица порядка M. Повернуть ее на 90о, 180о, 270о в положительном направлении.
Дана матрица размера N x M. Вывести количество строк столбцов, элементы которых монотонно возрастают, убывают.
Дана матрица размера N x M. Найти минимальный, максимальный среди элементов тех строк столбцов, которые упорядочены либо по возрастанию, либо по убыванию.
Дана матрица размера N x m. Поменять местами строки столбцы, содержащие минимальный и максимальный элементы матрицы.
В матрице А (m, n) найти строку с максимальной суммой элементов и строку с минимальной суммой элементов. Далее сформировать вектор В (2, m), у которого бы элементы чередовались с максимальной и минимальной строками.
Дана действительная квадратная матрица. Требуется преобразовать матрицу: поэлементно вычесть последнюю строку из всех строк, кроме последней.
Контрольные вопросы
Указать основные правила организации вложенных циклов.
Указать способы выхода из внутреннего цикла.
Как организовать вывод матрицы в общепринятом виде?
Как организовать вывод нижней треугольной матрицы в общепринятом виде?
Как организовать ввод матрицы размером N x M элементов?
Верно ли утверждение, что индекс массива должен иметь тип float.
Лабораторная работа № 6. Использование пользовательских функций
Цель работы: овладеть навыками программирования задач с использованием функций пользователя различных видов.
Краткие теоретические сведения
В практике программирования часто встречаются случаи, когда в программе приходится выполнять одни и те же вычисления, но при различных исходных данных. Для исключения повторений одинакового кода и упрощения программы, повторяющиеся вычисления выделяют в самостоятельную часть программы, которая может быть использована многократно по мере необходимости. Такая автономная часть программы, реализующая определенный алгоритм, оформленная в виде отдельной синтаксической конструкции, снабжённая именем и допускающая обращение к ней из различных частей общей программы, называется подпрограммой. Подпрограмма - это последовательность операторов, которые определены и записаны только в одном месте программы, однако их можно вызвать для выполнения из одной или нескольких точек программы.
Существует две категории подпрограмм: процедуры и функции.
Процедура — это подпрограмма, которая не возвращает через своё имя результата работы, поэтому она вызывается как отдельный оператор. Процедура «общается с внешним миром» через список параметров. Часть из них будут входными, часть — выходными, т.е. результатом работы.
Функция — это подпрограмма, которая через имя возвращает результат своей работы. Функция вызывается в выражении, а не как отдельный оператор. Через список параметров она может получить входные данные и вернуть результаты работы.
Формально в языках С/С++ нет процедур, а имеются только функции. Если же необходима именно процедура, то достаточно создать функцию, возвращающую тип void.
Чтобы использовать в программе свою собственную функцию, необходимо выполнить три действия:
задать прототип функции;
вызвать функцию в необходимом месте, например, в функции main()
дать определение функции.
Прототип функции — это заголовок функции, который заканчивается точкой с запятой. Прототипы всех функций, используемых в программе, обычно записывают в начале текста программы до определения функций. Прототип необходим для того, чтобы у компилятора была полная информация о типе результата работы функции и о списке параметров, передаваемых в функцию. Когда в тексте программы встретится обращение к функции, то компилятор проверяет правильность её вызова, сверяясь с информацией из прототипа.
Вызов функции возможен в любой функции, где это потребуется. Если тип результата функции — void, то вызов записывается отдельным оператором, в остальных случаях — в выражении того же типа, что и тип результата функции. В прочем, языки С/С++ позволяют записать вызов функции в виде отдельного оператора даже в том случае, когда она возвращает тип результата, отличного от void.
Определение функции состоит из её заголовка и тела, записанного в виде блока.
void main (void) //-----------> тип имя (список_параметров)
{ int count; //---------------------------> объявления_переменных; for (count = 0; count < 10; count++) cout << count << ' '; // -----> Оператор }
Допустимо записывать определение функций в любой последовательности. Нельзя определять функцию внутри другой функции.
В работе с подпрограммами приходится иметь дело с двумя видами параметров: список фактических параметров и список формальных параметров.
Список параметров (фактических или формальных — всё равно) записывается в круглых скобках сразу за именем функции. Список параметров может быть пустым, но скобки за именем функции обязательны!
Список фактических параметров — это те реальные данные, с помощью которых можно настроить алгоритм подпрограммы на обработку конкретных данных. Фактические параметры указываются в списке параметров при вызове функции и передаются в эту функцию.
Список формальных параметров — это набор требований, которые предъявляет подпрограмма к передаваемым в неё данным. Список фактических параметров записывается в заголовке функции при её определении в скобках. Для каждого параметра необходимо указать тип и имя. Имена формальных параметров локализованы в подпрограмме и дополняют перечень локальных объектов этой подпрограммы.
Между списками фактических и формальных параметров должно выдерживаться полное соответствие по количеству параметров, их типу, порядку следования и способу передачи в функцию. Несоблюдение этих требований в лучшем случае (для программиста) приводит к ошибке на стадии компиляции.
Задание
1. Изучить:
а) правила записи функций различных видов и способов обращений к ним;
б) способы передачи параметров в функцию;
в) порядок выполнения программ, использующих функции.
2. Разработать алгоритм решения в соответствии с заданием.
3. Составить программу решения задачи.
Пример выполнения работы
Условие: Найти максимум из двух чисел. Алгоритм поиска максимума оформить в виде функции.
#include <iostream>
using namespace std;
// 1)Прототип функции
double fmax(double a, double b);
int main()
{
double a = 4, b = 3, max;
cout << "a=" << a << " max=" << b << endl;
// 2)Вызов функции
max = fmax(a, b);
cout << "max=" << max << endl;
return 0;
}
// 3)Определение функции
double fmax(double x, double y)
{
double max;
if(x > y)
max = x;
else
max = y;
return max;
}
Условие: Определить длину окружности и площадь круга по известному радиусу. Определение длины окружности и площади круга оформить в виде отдельных функций.
#include <stdio.h> //Директива препроцессора
#define PI 3.1415 //Директива препроцессора
double circlen(double r); //Прототип функции circlen
double circsqr(double r); //Прототип функции circsqr
void main()
{
double r=1; //Объявление переменной r с инициализацией
double len; //Объявление переменной len с инициализацией
len = circlen (r); //Вызов функции circlen
printf("Length=%.1lf\n",len); //Печать результата на экране
double s;
s= circsqr (r); //Вызов функции circsqr
printf("Square = %.1lf\n",s);
}
/*
Функция circlen() возвращает длину окружности радиуса r
*/
double circlen (double r)
{
double d;
d=2*PI*r;
return d;
}
/*
Функция circsqr() возвращает площадь круга с радиусом r
*/
double circsqr (double r)
{
double p;
p=PI*r*r;
return p;
}
Задания для самостоятельного выполнения
Лабораторные работы 3 и 4 выполнить с использованием пользовательских функций.
Контрольные вопросы
Какие действия следует выполнить, чтобы использовать функцию для решения задачи?
Как описывается функция?
Как объявляется функция?
Роль прототипа?
Для чего нужны формальные параметры?
Как вызывается функция?
Способы передачи параметров?
Приемы передачи параметров-массивов?
Как передать результаты вычислений из функции?
Как используется тип void в описании функций?
В каких целях можно использовать оператор return?
Передача значений параметров по умолчанию?
Указать, при каких условиях целесообразно использовать функции, какие выгоды они предоставляют пользователю.
Запишите общий формат объявления функции.
Указать, в чем отличие различных видов функций пользователя.
Указать способ обращения к функциям пользователя.
Указать способы передачи параметров в функцию.
Указать способы передачи одномерного массива в функцию.
Перечислить, как согласуются формальные и фактические параметры.
Пояснить, как и куда осуществляется выход из подпрограммы.
Лабораторная работа № 7. Указатели. Динамическое управление памятью
Цель работы: научиться выделять и использовать динамическую память в процессе работы программы.
Краткие теоретические сведения
Указатель — это без знаковое целое, используемое для хранения адреса какого-либо участка памяти. Указатель всегда является переменной величиной. Всякий указатель используется для работы с данными, которые имеют какой-то свой тип и, соответственно, свой размер, например, double или int. Формальное описание указателя такое:
Тип_данных * Имя_указателя;
где
Тип_данных — любой ранее определённый тип (стандартный или пользовательский);
* — знак «звёздочка» здесь является признаком того, что речь идёт об указателе;
Имя_указателя — определяется по общим правилам (как для любого идентификатора пользователя).
Запись double *u; необходимо понимать: «u — это указатель на объект типа double». Значение указателя u в момент выделения памяти не определено. Запись double a = 2.5; u = &a; настраивает указатель на переменную а. Здесь знак & означает вычисление адреса, т.е. мы вычисляем адрес переменной a и записываем его в ячейку u. Если применить операцию разыменования:
cout << *u << endl;
этим оператором мы выводим на экран монитора содержимое переменной a, т.к. указатель u настроен на эту же переменную a. Можно и изменить значение переменной a, используя указатель u:
*u = 11.3;
cout << a << endl;
С помощью указателей можно создавать динамические массивы — это массивы, память для которых выделяется не на этапе компиляции, а во время исполнения программы. Для динамического выделения памяти служит операция new, освобождение ставшей ненужной памяти выполняется операцией delete.
Указатель = new Тип [Количество_элементов];
где Тип — это тот же тип данных, что и тип, на который рассчитан указатель.
Запись оператора для освобождения динамической памяти:
delete [] Указатель;
Здесь пустые квадратные скобки — это признак того, что освобождается память, отводимая для массива, а не для одиночного объекта.
Так как строк в матрице может быть достаточно много, а указатели, используемые для выделения памяти под каждую строку матрицы, имеют один и тот же тип, то эти указатели есть смысл объединить в одномерный массив указателей. Естественно, память под массив указателей также будем выделять динамически. А адрес этого массива указателей будем хранить в указателе на указатель. На рисунке 8 покажем, как это может выглядеть:
Рис.
8. Создание динамического массива
Здесь a — это указатель на массив указателей. Формальное описание для него:
Тип ** имя_указателя; a[i] — указатели на строки матрицы, в которых будут в дальнейшем хранится данные, т.е. элементы матрицы a[i][j].
Задание
1. Изучить: правила использования динамической памяти; указатель и его назначение; формат определения указателя; способы инициализации указателя; операции над указателями; связь массива с указателем; способы доступа к элементам массива через указатель; оператор косвенного доступа.
2. Разработать алгоритм решения в соответствии с заданием.
3. Составить программу решения задачи.
4. Подготовить тестовый вариант программы и исходных данных.
Создавая динамический массив, следует позаботиться о достаточном количестве памяти для размещения его элементов. Следует помнить, что освобождать можно только ту память, которая была ранее выделена. В задачах, требующих создания нового динамического массива, необходимо предусмотреть случай, когда в формируемом массиве может не оказаться ни одного элемента. Такую ситуацию надо обрабатывать отдельно.
Пример выполнения работы
Условие: Дана матрица, используя динамическую память, составить программу ввода элементов матрицы с клавиатуры и вывод ее на экран монитора.
Объявим переменные n и m, которые задают размер матрицы; переменную a, которая является указателем на указатель для выделения динамической памяти; переменные i и j для индексов строк и столбцов матрицы. Для матрицы выделяется динамическая память; в память для матрицы с клавиатуры введены числа.
void main()
{
int n, m; // Переменные для размера матрицы не определены.
int **a; // Определяем a-указатель на указатель для динамической
// памяти матрицы.
int i,j;
clrscr();
cout << “Введи количество строк и количество столбцов матрицы: ”;
cin >> n >> m; // Вводится размер матрицы.
a = new int *[n]; // Выделяется память под массив указателей.
for ( i = 0; i < n; i++)
a[i] = new int[m]; // Выделяется память под элементы i-той строки
cout << “Введи элементы матрицы:\n”;
for ( i = 0; i <= n-1; i++ )
for ( j = 0; j <= m-1; j++)
{ printf("a[ %d, %d ]= ", i, j); // Поясняющий текст.
scanf( " %d", &a[i][j] ); }
cout << “Введена матрица:\n”;
for ( i = 0; i <= n-1; i++ )
{ for ( j = 0; j <= m-1; j++)
printf("%d ",a[i][ j]); // Вывод элемента i-той строки матрицы.
printf(“\n”); // Перевод курсора на новую строку монитора.
}
getch(); }
Условие: Пусть задан одномерный массив вещественных чисел x[0], x[1], ... , x[n-1] (n - заданное натуральное число). Требуется получить и распечатать элементы этого массива в следующем порядке: x[k+1], x[k+2], ... , x[n-1], x[0], x[1], ..., x[k], (где k - индекс первого по порядку максимального элемента массива x). Физическое расположение в памяти элементов массива x не изменять. Для решения задачи использовать вспомогательный массив указателей.
#include <windows.h>
#include <wincon.h>
#include <stdio.h>
#include<time.h>
#include<stdlib.h>
void printp(int** p, int n);
void print(int* x, int n);
void rnd_vector(int* x, int n, int a, int b);
int ind_max(int* x, int n);
void formp(int* x, int** p, int n, int k);
void main()
{
SetConsoleOutputCP(1251);
srand ((unsigned)time(NULL));
const int n=10;
int a[n];
int imax; //Индекс максимального элемента массива
rnd_vector(a,n,1,50);
print(a,n);
puts("");
imax=ind_max(a,n);
int* r[n];
formp(a,r,n,imax);
printp(r,n);
}
/*
Функция заполняет массив x, состоящий из n элементов, случайными целыми числами из промежутка [a; b].
*/
void rnd_vector(int* x, int n, int a, int b )
{
for (int i=0;i<n;i++)
x[i]=(int)((double)rand()/RAND_MAX*(b-a+1)+a);
}
/*
Функция печатает массив x, состоящий из n элементов, на экране.
*/
void print(int* x,int n)
{
int i;
for(i=0; i<n; i++)
printf("%4d",x[i]);
puts("");
}
/*
Функция возвращает индекс первого по порядку максимального элемента массива x размера n.
*/
int ind_max(int* x, int n)
{
int max, ind;
max=x[0];
ind=0;
for( int i=0; i<n; i++)
if (x[i]>max)
{
max=x[i];
ind=i;
}
return ind;
}
/*
Функция печатает на экране значения, размещённые по адресам p[0], p[1], …, p[n-1], где p - массив, каждый элемент которого есть указатель на тип int, n – размер массива p.
*/
void printp(int** p, int n)
{
int i;
for(i=0; i<n; i++)
printf("%4d",*p[i]);
puts("");
}
/*
Функция заполняет массив указателей p адресами элементов массива x по заданному правилу (см. условие задачи).
n – размер массива p и массива x; k – индекс первого по порядку максимального элемента массива x.
*/
void formp(int* x, int** p, int n, int k)
{
int i,j;
for ( i=0, j=k+1; j<n ; i++,j++)
p[i]=&x[j];
for ( j=0; j<=k ;i++,j++)
p[i]=&x[j];
}
Условие: Задан одномерный массив целых чисел x. Получить новый массив y, состоящий из тех элементов массива x, которые кратны 7. Порядок следования и количество повторений этих чисел в исходном массиве сохранить. Оба массива разместить в динамической памяти.
Например:
x: 35, 11, 10, 7, 11, 35.
y: 35, 7, 35.
#include <windows.h>
#include <wincon.h>
#include <stdio.h>
#include<time.h>
#include<stdlib.h>
int* rand_array(int n,int a, int b);
void print_array(int*x, int n);
void main()
{
SetConsoleOutputCP(1251);
srand ((unsigned)time(NULL));
int n;
puts("Введите число элементов исходного массива:");
scanf("%d",&n);
int*a; //Объявлен указатель на исходный массив
a=rand_array(n,0,50);
puts("Исходный массив:");
print_array(a,n);
int k=0;
for (int i=0;i<n;i++)
if (a[i]%7==0)
k++;
if (k==0)
{
puts("Новый массив пустой.");
free(a);
return;
}
int*b; // Указатель на массив-результат
b=(int*)malloc(k*sizeof(int));
k=0;
for (i=0;i<n;i++)
if (a[i]%7==0)
b[k++]=a[i];
puts("Новый массив:");
print_array(b,k);
free(a);
free(b);
}
/*
Функция создаёт динамический массив из n элементов, заполняет его случайными целыми числами из промежутка [a;b] и возвращает указатель на начало этого массива.
*/
int* rand_array(int n,int a, int b)
{
int*x;
x=(int*)malloc(n*sizeof(int));
for (int i=0; i<n; i++)
x[i]=(int)((double)rand()/RAND_MAX*(b-a+1)+a);
return x;
}
/*
Функция печатает массив x на экране.
*/
void print_array(int* x, int n)
{
for (int i=0; i<n; i++)
printf("%5d", x[i]);
puts("");
}
Задания для самостоятельного выполнения
Обязательно использовать динамическую память.
1. Дополнить матрицу строкой, содержащей максимумы по столбцам.
2. Дополнить матрицу столбцом, содержащим максимумы по строкам.
3. Вычислить произведение двух матриц.
4. Вычислить произведение матрицы на вектор.
5. Транспонировать матрицу.
6. Найти максимальный элемент матрицы.
7. По заданной матрице составить вектор, элементы которого равны суммам элементов соответствующей строки.
8. По заданной матрице составить вектор, элементы которого равны суммам элементов соответствующего столбца.
9. По заданной матрице составить вектор, элементы которого равны произведениям элементов соответствующей строки.
10. По заданной матрице составить вектор, элементы которого равны произведениям элементов соответствующего столбца.
11. Поменять местами строки матрицы с номерами i и j.
12. Поменять местами столбцы матрицы с номерами i и j.
13. В матрице найти строку, состоящую только из отрицательных чисел.
14. Проверить матрицу на симметричность.
15. Проверить совпадение двух матриц.
16. Найти минимальный элемент матрицы.
17. Проверить, является ли матрица верхней треугольной.
18. Удалить из матрицы дублирующие строки.
19. Удалить из матрицы дублирующие столбцы.
20. Проверить, является ли матрица нижней треугольной.
21. Подсчитать количество различных элементов матрицы.
22. В матрице найти столбец, состоящий только из отрицательных чисел.
23. Определить в матрице строку с наименьшей суммой элементов.
24. Определить в матрице столбец с наименьшей суммой элементов.
25. Заменить в матрице строку с номером i на сумму строк с номерами i и j. Строку с номером j удалить.
26. Определить номер строки матрицы, в которой находится максимальная сумма элементов столбцов с номером k и l.
27. Определить в матрице строки, элементы которых расположены по возрастанию.
Контрольные вопросы
1. Указать основные правила организации вложенных циклов.
2. Указать способы выхода из внутреннего цикла.
3. Как организовать вывод матрицы в общепринятом виде?
4. Как организовать вывод нижней треугольной матрицы в общепринятом виде?
5. Как организовать ввод матрицы размером N x M элементов?
6. Что такое указатель?
7. Как объявить указатель заданного типа с именем p?
8. Можно ли инициализировать указатель кодом int *p = 0 ?
9. Можно ли инициализировать указатель кодом int *p = NULL ?
10. Дан код int *p. Объясните результат выполнение директивы p = new int;
11. Дан код int *p. Объясните результат выполнения директив:
p = new int;
p = new int;
p = new int;
p = new int;
p = new int;
12. Дан код int *p. Можно ли записать следующий оператор: p = p + 5;
13. Дан код int *p. Объясните результат выполнения директивы cout << *p.
14. Чем отличается указатель типа int от указателя типа float.
15. Дан код int x = 2; Можно ли записать директиву cout << *(&x) и
если да, то какой результат появится на экране.
16. Дан код int x[10]. Объясните результат выполнения кода cout << x.
17. Дан код int x[10]. Можно ли записать выражение x – &x[5] и если да, чему равно значение данного выражения.
18. Дан код int *p, x[10]; Можно ли записать p = x.
19. Даны коды int *p, x[10]; p = x; Можно ли записать p++, x++.
20. Дан код int x[10], i. Объясните результат выполнения кода cout << (x+i).
21. Дан код int x[10], i.Чему равен результат выражения *(x+i) == x[i].
22. Дан код int x[10], i.Чему равен результат выражения *(x+i) < x[i]
23. Дан код int *p. Объясните результат выполнения директивы cout << p.
24. Дан код int x[10], i.Чему равен результат выражения (x+i) < &x[i]
25. Дан код int *x[10]. Объясните результат выполнения данного кода.
26. Как связано понятие указателя с понятием косвенного доступа к информации?
27. Связь двумерного массива с указателем.
Лабораторная работа № 8. Программирование с использованием строк
Цель работы: овладеть навыками программирования задач с использованием строк.
Краткие теоретические сведения
Для представления символов в памяти компьютера используется тип char. Определение констант и переменных этого типа:
const char c1 = 'A';// константная переменная
char c = c1, c2; // переменные
Под данные типа char отводится 1 байт. Тип char является целым типом, поэтому внутреннее представление для данных типа char (их коды) — это просто целые числа.
Для работы с данными типа char можно использовать все арифметические операции, операции сравнения и побитовые операции, хотя, если учесть, что этот тип используется для представления не чисел, а именно символов, то, естественно, чаще всего применяют операции сравнения.
В языках С/С++ нет встроенного строкового типа данных. Для работы со строками используется массив данных типа char. Если подразумевается, что работа ведётся не просто с массивом символов, а со строкой, то она должна заканчиваться символом с кодом 0 ('\0' — нуль-символ). Именно нуль-символ показывает, где заканчиваются данные в таком массиве.
Пусть дана строка s (рис. 9):
Рис. 9. Строка символов
Памяти под неё отводится 6 байт, поэтому описание будет следующим:
char s[6];
Полезная информация (текст "ABC") размещается в первых трёх байтах, а затем в третьем байте находится нуль-символ '\0'.
Строку s можно было бы инициализировать, т.е. на этапе компиляции задать ей начальное значение:
char s[6] = {'A', 'B', 'C', '\0'};
Так как s — это массив (хотя и символов), поэтому инициализация записана точно так же, как это обычно делается для массива. Но s — это ещё и строка, поэтому допускается упрощённый вариант инициализации, схожий с инициализацией простых переменных:
char s[6] = "ABC";
При инициализации для строки допустимо не задавать объём выделяемой памяти:
char s[] = "ABC";
Теперь компилятор сам подсчитает, сколько требуется отвести памяти под строку, и выделит под неё необходимый объём. Функции для работы со строками и символами представлены в таблице 3.
Таблица 3
Функции для работы со строками и символами
Функция |
Пояснение |
strlen(имя_строки) |
определяет длину указанной строки, без учёта нуль-символа |
strcpy(s1,s2) |
выполняет побайтное копирование символов из строки s2 в строку s1 |
strncpy(s1,s2, n) |
выполняет побайтное копирование n символов из строки s2 в строку s1. возвращает значения s1 |
strcat(s1,s2) |
объединяет строку s2 со строкой s1. Результат сохраняется в s1 |
strncat(s1,s2,n) |
объединяет n символов строки s2 со строкой s1. Результат сохраняется в s1 |
strcmp(s1,s2) |
сравнивает строку s1 со строкой s2 и возвращает результат типа int: 0 –если строки эквивалентны, >0 – если s1<s2, <0 - если s1>s2 С учётом регистра |
strncmp(s1,s2) |
сравнивает n символов строки s1 со строкой s2 и возвращает результат типа int: 0 –если строки эквивалентны, >0 – если s1<s2, <0 - если s1>s2 С учётом регистра |
stricmp(s1,s2) |
сравнивает строку s1 со строкой s2 и возвращает результат типа int: 0 –если строки эквивалентны, >0 – если s1<s2, <0 - если s1>s2 Без учёта регистра |
strnicmp(s1,s2) |
сравнивает n символов строки s1 со строкой s2 и возвращает результат типа int: 0 –если строки эквивалентны, >0 – если s1<s2, <0 - если s1>s2 Без учёта регистра |
isalnum(c) |
возвращает значение true, если с является буквой или цифрой, и false в других случаях |
isalpha(c) |
возвращает значение true, если с является буквой, и false в других случаях |
продолжение табл. 3
isdigit(c) |
возвращает значение true, если с является цифрой, и false в других случаях |
islower(c) |
возвращает значение true, если с является буквой нижнего регистра, и false в других случаях |
isupper(c) |
возвращает значение true, если с является буквой верхнего регистра, и false в других случаях |
isspace(c) |
возвращает значение true, если с является пробелом, и false в других случаях |
toupper(c) |
если символ с, является символом нижнего регистра, то функция возвращает преобразованный символ с в верхнем регистре, иначе символ возвращается без изменений. |
strchr(s,c) |
поиск первого вхождения символа с в строке s. В случае удачного поиска возвращает указатель на место первого вхождения символа с. Если символ не найден, то возвращается ноль. |
strcspn(s1,s2) |
определяет длину начального сегмента строки s1, содержащего те символы, которые не входят в строку s2 |
strspn(s1,s2) |
возвращает длину начального сегмента строки s1, содержащего только те символы, которые входят в строку s2 |
strprbk(s1,s2) |
Возвращает указатель первого вхождения любого символа строки s2 в строке s1 |
atof(s1) |
преобразует строку s1 в тип double |
atoi(s1) |
преобразует строку s1 в тип int |
atol(s1) |
преобразует строку s1 в тип long int |
getchar(с) |
считывает символ с со стандартного потока ввода, возвращает символ в формате int |
gets(s) |
считывает поток символов со стандартного устройства ввода в строку s до тех пор, пока не будет нажата клавиша ENTER |
Задание
1. Составить блок-схему алгоритма и программу в соответствии с заданным вариантом.
2. Составить отчет о проделанной работе (аналогично отчету для лабораторной работы №1)
Пример выполнения работы
Условие: Поменять порядок символов, расположенных между первой и последней точкой, на обратный.
#include <windows.h>
#include <wincon.h>
#include <stdio.h>
#include<stdlib.h>
char* srev(char* str);
void main()
{
SetConsoleOutputCP(1251);
char str[50]="In.for mat i.ka ";
puts(str);
srev(str);
puts(str);
}
/*
Функция меняет в строке str порядок символов, расположенных между первой и последней точкой, на обратный.
*/
char* srev(char* str)
{
char* first,*last;
first=strchr(str,'.'); //Адрес первой точки
last=strrchr(str,'.'); //Адрес последней точки
//Если точек нет или она одна, строку не меняем:
if (first==NULL || first==last)
return str;
//На время “обрезаем” строку:
*last='\0';
strrev(first+1);
//Восстанавливаем последнюю точку:
*last='.';
return str;
}
Задания для самостоятельного выполнения
Определить, содержит ли текст символы, отличные от малых латинских букв и пробела.
Выяснить, является ли заданный текст идентификатором.
Если в тексте нет символа * , то оставить этот текст без изменения, иначе каждую из малых латинских букв, предшествующих первому вхождению символа *, заменить на цифру 3.
Если в тексте нет символа + , то оставить этот текст без изменения, иначе каждую из цифр, предшествующих первому вхождению символа +, заменить символом -.
Если в тексте нет малых латинских букв, то оставить его без изменения, иначе каждый из символов, следующих за первой группой малых латинских букв, заменить точкой.
Подсчитать количество русских гласных букв в последнем слове текста.
Подсчитать количество цифр в первом слове текста.
В каждом из слов текста заменить первую букву звездочкой.
Первое слово текста заменить тремя звездочками.
Последнее слово текста заменить тремя звездочками.
Заменить каждую цифру, расположенную между первой и последней точкой, символом ‘*’.
Пусть первая часть текста есть все символы, расположенные до первого встретившегося пробела. Вторая часть - все остальные. Поменять местами первую и вторую части текста.
Даны две строки. Вставить все символы второй строки в первую строку, поместив их после символа с заданным индексом.
Даны две строки. Если первое слово одной строки совпадает с первым словом другой строки, то удалить первое слово той строки, длина которой больше. Иначе оставить строки без изменения.
Контрольные вопросы
1. Указать, какие операции можно выполнять над символьными данными.
2. Указать способ описания символьных данных.
3. Назвать специальные функции, используемые для обработки символьных данных.
4. Для чего используется тип данных char.
5. При инициализации для строки допустимо ли не задавать объём выделяемой памяти.
6. Какие операции можно использовать для работы с типом данных char.
7. Что означает символ '\0'.
Лабораторная работа № 9. Работа со структурами
Цель работы: научиться определять структуры, освоить формат доступа к элементам структуры и к элементам массива структур.
Краткие теоретические сведения
Структуры помогают группировать связанные данные под одним именем. С помощью структуры можно создать некоторую составную переменную, содержащую в себе набор некоторых параметров, после чего эта переменная будет равносильна новому типу данных. Для определения структуры используют ключевое слово struct, за которым обычно следует имя и левая фигурная скобка. Следом за открывающей фигурной скобкой указывают тип и имя одного или нескольких элементов. За последним элементом размещают правую закрывающую фигурную скобку. В этот момент можно (необязательно) объявить переменные данной структуры:
struct name
{ int member_name_l ; | ———— Объявления элементов структуры float member_name_2; } variable; | ———— Объявление переменной }
Ключевое слово struct является обязательным при программировании на С, однако в C++ использовать ключевое слово struct необязательно. Пусть дана структура:
struct book {
char title[100]; //наименование книги
char author[100]; //автор
int year; //год издания
};
Для того чтобы объявить переменную для структуры с именем book используется такая запись:
struct book lib; //объявляется переменная типа book
После объявления переменной lib имеется возможность работать со структурой как с единым объектом данных, который имеет три поля: title, author и year. Обращение к тому или иному полю структуры осуществляется через точку: lib.title, lib.author и lib.year. Таким образом, для записи в структуру информации можно использовать следующий фрагмент программы:
printf(“Введите наименование книги: “);
scanf(“%s”,lib.title);
printf(“Введите автора книги: “);
scanf(“%s”,lib.author);
printf(“Введите год издания книги: “);
scanf(“%d”,&lib.year);
После этого в соответствующие поля будет записана введенная с клавиатуры информация и хранится в единой переменной lib.
Если функция не изменяет структуру, вы можете передать структуру в функцию по имени. Если функция изменяет элемент структуры, вы должны передавать эту структуру в функцию с помощью адреса. Для передачи переменной типа структуры с помощью адреса вы просто предваряете имя переменной оператором адреса C++ (&), как показано ниже:
some_function(&worker);
Внутри функции, которая изменяет один или несколько элементов, вам следует работать с указателем. Если вы используете указатель на структуру, легче всего обращаться к элементам структуры, используя следующий синтаксис:
pointer_variable->member = some_value;
Задание
1. Составить блок-схему алгоритма и программу в соответствии с заданным вариантом.
2. Составить отчет о проделанной работе (аналогично отчету для лабораторной работы №1)
Пример выполнения работы
Условие: В соревнованиях по фигурному катанию участвуют пары из разных городов. Имеются следующие сведения о каждой паре:
- фамилии, имена партнеров;
- город, откуда прибыла данная пара;
- оценки, полученные в обязательной программе (всего 10 судей, каждый судья выставляет паре по одной оценке).
Подсчитать процент иногородних пар (допустим, что соревнования проходят в городе N).
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include <windows.h>
#include <wincon.h>
#define CB 10 //Число судей
struct Sport
{
char* name;
char* town;
int ball[CB];
};
void print_sp(struct Sport* sp, int n);
double procent(struct Sport* sp, int n, char*t);
void main()
{
SetConsoleOutputCP(1251);
const int n=5;
struct Sport spms[n]=
{
{"Ivanov Ivanova", "Moscow", {5,6,5,4,5,6,6,8,3,2}},
{"Petrov Petrova", "Kiev", {4,7,7,8,9,10,6,6,7,3}},
{"Sidorov Sidorova", "Tomsk", {4,6,7,8,9,10,6,7,7,2}},
{"Kotov Kotova", "Lipetsk", {2,4,6,7,8,9,5,6,7,3}},
{"Frolov Frolova", "Moscow", {5,7,5,7,5,4,6,8,3,2}}
};
print_sp(spms,n);
char str[]="Moscow";
double pri;
pri=procent(spms,n,str);
printf("Процент иногородних пар = %lf",pri);
}
/*
Функция выводит на экран массив элементов типа struct Sport.
*/
void print_sp(struct Sport* sp,int n)
{
int i,j;
for(i=0;i<n;i++)
{
printf("%-18s%-10s",sp[i].name,sp[i].town);
for(j=0;j<CB;j++)
printf("%2d",sp[i].ball[j]);
puts("");
}
}
/*
Функция возвращает процент иногородних пар.
sp – исходный массив структур из n элементов;
t – строка, содержащая название города, в котором проходят соревнования.
*/
double procent(struct Sport* sp,int n, char*t)
{
int count = 0;
int i;
for(i=0;i<n;i++)
if(strcmp(sp[i].town, t) != 0)
count++;
double pr;
pr=((double)count/n)*100;
return pr;
}
Задания для самостоятельного выполнения
Создать структуру «студент» со следующими данными: фамилия, имя, отчества, пол, факультет, курс, группа, отметки по пяти предметам, город (село) проживания. Сформировать текстовый файл со списком студентов. Для каждого пункта характеристики студента выделять строку. Данные о студентах отделяются друг от друга пустыми строками. Для выполнения задания данные из текстового файла ввести в массив структур программы.
1. Сформировать список студентов, в котором студенты-задолжники расположены по алфавиту. Список выдать на экран. Студентов-задолжников при выводе пометить.
2. Сформировать список студентов, в котором студенты-задолжники по двум предметам расположены по алфавиту. Список выдать на экран. Студентов-задолжников при выводе пометить.
3. Сформировать список студентов, в котором студентки-отличницы расположены по алфавиту. Список выдать на экран. Студенток-отличниц при выводе пометить.
4. Сформировать список студентов, в котором студентки-отличницы, проживающие в городе Ачинске и имеющих пятерки, расположены по алфавиту.
5. Сформировать список студентов, в котором студенты расположены по алфавиту мест проживания. Список выдать на экран.
6. В редакции телепрограмм имеются следующие сведения о передачах, выходящих в эфир в течение суток:
название передачи;
жанр передачи (например, художественный фильм, реклама; информационная программа, детская передача и т.д.);
время выхода в эфир (начало - часы, минуты, конец - часы, минуты).
Подсчитать количество художественных фильмов, показанных за эти сутки.
В редакции телепрограмм имеются следующие сведения о передачах, выходящих в эфир в течение суток:
название передачи;
жанр передачи (например, художественный фильм, реклама; информационная программа, детская передача и т.д.);
время выхода в эфир (начало - часы, минуты, конец - часы, минуты).
Подсчитать суммарную длительность рекламы за сутки.
В таблице собраны следующие сведения о государствах Африки:
название государства;
территория (в тыс. кв. км);
численность населения (в млн. чел.);
имеется ли морская граница (да, нет);
столица.
Подсчитать количество стран, численность населения которых превышает заданную величину.
В таблице собраны следующие сведения о государствах Африки:
название государства;
территория (в тыс. кв. км);
численность населения (в млн. чел.);
имеется ли морская граница (да, нет);
столица.
Среди государств, имеющих морскую границу, определить то, численность населения которого максимальна.
10. В таблице собраны следующие сведения о государствах Африки:
название государства;
территория (в тыс. кв. км);
численность населения (в млн. чел.);
имеется ли морская граница (да, нет);
столица.
Среди государств, имеющих морскую границу, определить самое большое по занимаемой территории.
В магазине детских товаров есть сведения об имеющихся в продаже игрушках:
название игрушки (например, кукла, мяч, конструктор и т.п.);
адрес завода-изготовителя (город, улица, номер дома);
стоимость игрушки (в рублях);
возрастная категория, на которую ориентирована данная игрушка (например, от 2 до 5 лет);
может ли игрушка использоваться для спортивных игр (да или нет).
Определить суммарную стоимость игрушек, предназначенных для спортивных игр (по одной каждого наименования).
В соревнованиях по фигурному катанию участвуют пары из разных городов. Имеются следующие сведения о каждой паре:
фамилии, имена партнеров;
город, откуда прибыла данная пара;
оценки, полученные в обязательной программе (всего 10 судей, каждый судья выставляет паре по одной оценке).
Определить количество пар из города N, участвующих в соревновании.
В школьной администрации имеется следующая информация о каждом выпускнике 11 классов:
фамилия, имя, отчество;
дата рождения (год, месяц, число);
домашний адрес (улица, дом, квартира);
оценки аттестата о среднем образовании.
Определить, есть ли в этом списке выпускник Белкин Сергей Ильич.
Контрольные вопросы
1. Где может быть использована структура?
2. Как называются элементы структуры?
3. Как определить структуру?
4. Может ли структура содержать элементы одного типа?
5. Как обратиться к полям структуры?
6. Как обратится к элементу массива структур?
7. Какое ключевое слово начинает определение структуры?
8. Как обратиться к полям структуры через указатель на нее?
9. При помощи какой операции формируется доступ к полям структуры?
10. Какая разница между определениями структуры и массива?
11. Опишите объект, для которого надо определить структуру и опре-
делите ее.
Лабораторная работа № 10. Работа с файлами
Цель работы: овладеть навыками алгоритмизации и программирования файловых структур данных; научиться проектировать структуры файла, запись данных в файл, ввод данных из файла.
Краткие теоретические сведения
Используя класс ostream, программы могут выполнять вывод в cout с использованием оператора вставки или различных методов класса, например cout.put. Заголовочный файл iostream.h определяет выходной поток cout. Аналогично, заголовочный файл fstream.h определяет класс выходного файлового потока с именем ofstream. Используя объекты класса ofstream, программы могут выполнять вывод в файл. Для начала необходимо объявить объект типа ofstream, указав имя требуемого выходного файла как символьную строку:
ofstream file_object("FILENAME.EXT");
Если указано имя файла при объявлении объекта типа ofstream, C++ создаст новый файл на диске, используя указанное имя, или перезапишет файл с таким же именем, если он уже существует на вашем диске.
#include <fstream.h>
void main(void)
{ ofstream book_file("BOOKINFO.DAT");
book_file << "Учимся программировать, " << "Вторая редакция"
<< endl;
book_file << "Jamsa Press" << endl;
book_file << "22.95" << endl;
}
Подобным образом ваши программы могут выполнить операции ввода из файла, используя объекты типа ifstream. Опять же, вы просто создаете объект, передавая ему в качестве параметра требуемое имя файла:
ifstream input_file("file name.EXT");
Чтобы определить конец файла, ваши программы могут использовать функцию еоf потокового объекта. Эта функция возвращает значение 0, если конец файла еще не встретился, и 1, если встретился конец файла. Используя цикл while, ваши программы могут непрерывно читать содержимое файла, пока не найдут конец файла, как показано ниже:
while (! input_file.eof())
{
// Операторы
}
В данном случае программа будет продолжать выполнять цикл, пока функция eof возвращает ложь (0). Ниже приведен краткий обзор основных функций.
Ввод/вывод в С++ реализуется либо с помощью функций, унаследованных от библиотек С, либо с помощью потоков С++. Смешивать эти два способа в одной программе не рекомендуется.
Для использования функций ввода/вывода в стиле С необходимо подключить к программе заголовочный файл <stdio.h> или <cstdio>. При вводе/выводе данные рассматриваются как поток байтов. Физически поток представляет собой файл или устройство, например, клавиатуру или дисплей, рассматривающийся как частный случай файла. Работа с потоком начинается с его открытия. Поток можно открыть для чтения и/или записи в двоичном или текстовом режиме. Функция открытия потока имеет формат:
FILE* fopen(const char* filename, const char* mode);
При успешном открытии потока функция возвращает указатель на предопределенную структуру типа FILE, содержащую всю необходимую для работы с потоком информацию, или NULL в противном случае. Первый параметр — имя открываемого файла в виде С-строки, второй — режим открытия файла:
"r" — файл открывается для чтения;
"w" — открывается пустой файл для записи (если файл существует, он стирается);
"a" — файл открывается для добавления информации в его конец;
"r+" — файл открывается для чтения и записи (файл должен существовать);
"w+" — открывается пустой файл для чтения и записи (если файл существует, он стирается);
"a" — файл открывается для чтения и добавления информации в его конец.
Режим открытия может также содержать символы t (текстовый режим) или b (двоичный режим), отличающиеся обработкой символов перехода на новую строку. По умолчанию файл открывается в текстовом режиме, при котором комбинация символов "возврат каретки" и "перевод строки" (0x13 0x10) при вводе преобразуются в одиночный символ перевода строки (при выводе выполняется обратное преобразование). В двоичном режиме преобразования не выполняются.
FILE *f = fopen("d:\\cpp\\data.txt", "rb+");
Указатель f используется в дальнейших операциях с потоком. Его передают функциям ввода/вывода в качестве параметра.
При открытии потока с ним связывается область памяти, называемая буфером. При выводе вся информация направляется в буфер и накапливается там до заполнения буфера или до закрытия потока. Чтение осуществляется блоками, равными размеру буфера, и данные читаются из буфера. Ниже перечислены основные функции ввода/вывода потока.
Чтение и запись потока байтов выполняют функции fread и fwrite.
Чтение символа из потока — getc, fgetc, из стандартного потока stdin — getchar.
Запись символа в поток — putc, fputc, в стандартный поток stdout — putchar.
Чтение строки из потока — fgets, из стандартного потока stdin — gets.
Запись строки в поток — fputs, в стандартный поток stdout — puts.
Форматированный ввод из потока — fscanf, из стандартного потока stdin — scanf, из строки — sscanf.
Форматированный вывод в поток — fprintf, в стандартный поток stdout — printf, в строку — sprintf.
Поток закрывается либо при завершении программы, либо явным образом с помощью функции fclose:
int fclose(FILE*);
Перед закрытием потока информация из связанных с ним буферов выгружается на диск. Рекомендуется явным образом закрывать потоки, открытые для записи.
Задание
Изучить основную терминологию, связанную с файловыми структурами данных, возможности языка программирования по обработке файла с последовательной организацией: записи данных в файл, ввод из файла, до записи данных в файл и т. п.
Составить блок-схему алгоритма и программу в соответствии с заданным вариантом.
Составить отчет о проделанной работе (аналогично отчету для лабораторной работы №1)
Пример выполнения работы
В соревнованиях по фигурному катанию участвуют пары из разных городов. В файле, созданном в текстовом редакторе, имеются следующие записи о каждой паре:
- фамилии, имена партнеров;
- город, откуда прибыла данная пара;
- оценки, полученные в обязательной программе (всего 10 судей, каждый судья выставляет паре по одной оценке).
Подсчитать процент иногородних пар (допустим, что соревнования проходят в городе N).
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include <windows.h>
#include <wincon.h>
#define CB 10 //Число судей
#define MAXLEN 80 //Максимальная длина строки
struct Sport
{
char name[MAXLEN];
char town[MAXLEN];
int ball[CB];
};
int procent(char* filename, char* twn);
void main()
{
SetConsoleOutputCP(1251);
int result;
/*Пусть исходные данные для задачи содержатся в текстовом файле data.txt*/
result=procent("data.txt","Moscow");
if(result != -1)
printf("Процент иногородних пар = %d",result);
}
/*
Функция открывает файл с именем filename, считывает из него последовательно записи, вычисляет и возвращает процент иногородних пар (см. условие задачи). Параметр twn – указатель на строку, которая содержит название города, в котором проходят соревнования.
*/
int procent(char* filename, char* twn)
{
FILE* sp; // Указатель на поток
if((sp=fopen(filename,"r"))==NULL)
{
perror("");
return -1;
}
int i;
/*tmp – для считывания одной записи файла:*/
struct Sport tmp;
int count = 0; //Количество иногородних пар
int n = 0; //Количество всех пар-участников
while(1)
{
if(fscanf(sp,"%s%s",tmp.name,tmp.town) == EOF)
break;
for(i=0;i<CB;i++)
fscanf(sp,"%d",&tmp.ball[i]);
if (strcmp(tmp.town,twn) != 0)
count++;
n++;
}
fclose(sp);
int pr;
pr=(count*100)/n;
return pr;
}
Пример 2
Требуется сохранить массив структурных переменных по шаблону struct Book в двоичном файле.
#include"stdio.h"
#include"stdlib.h"
#define LEN 50
struct Book
{
char name[LEN];
char title[LEN];
int year;
};
void main()
{
//Объявляем указатель на открытый поток:
FILE*f;
//Объявляем массив структур с инициализацией:
const int n=4;
struct Book bibl[n]=
{{"Tolstoy", "Voina_and_mir", 1879},
{"Ostrovski", "Groza", 1965},
{"Zolya", "Nana", 1960},
{"Andersen", "Skazki", 1976}};
//Открываем файл list.dat для записи в двоичном режиме:
if((f=fopen("list.dat", "wb"))==NULL)
{
perror("Error");
exit(1);
}
int c;
//Записываем данные по шаблону Book в файл:
c=fwrite(bibl, sizeof(struct Book), n, f);
//Проверяем успешность записи данных:
if(c==n)
puts("Done.");
else
puts("Error!");
//Закрываем файл:
fclose(f);
}
Задания для самостоятельного выполнения
Обрабатываемый текст программа считывает из файла.
1. Подсчитать количество слов во введенном тексте.
2. Подсчитать количество предложений во введенном тексте.
3. Напечатать в столбик первые слова всех предложений текста.
4. Напечатать в столбик последние слова всех предложений текста.
5. Определить и напечатать слова максимальной длины.
6. Определить и напечатать слова минимальной длины.
7. Определить, в каком по счету предложении впервые встретилось заданное слово.
8. Напечатать предложение, в котором впервые встретилось заданное слово.
9. Напечатать последовательно все двойные буквы (в слове подряд две одинаковых).
10. Подсчитать количество букв, которые встретились в тексте двойными.
11. Напечатать текст, заменив все буквы е на буквы е.
12. Напечатать текст, выпустив все гласные буквы.
13. Напечатать последовательно все встретившиеся в тексте цифры.
14. Подсчитать количество встретившихся в тексте цифр.
15. Проверить правильность написания чисел в тексте. Встретившиеся в начале числа незначащие нули опустить. Исправленный текст напечатать.
16. Прочитать текст построчно справа налево, напечатать.
17. Напечатать текст, выпустив повторяющиеся пробелы между словами.
Контрольные вопросы
Объяснить, что означают следующие термины: файл, запись, метод
доступа, структура записи?
Каково назначение операторов открытия и закрытия файлов на языке
программирования?
Допустимы ли различные типы данных для элементов одной записи?
Указать, с помощью, каких операторов выполняется запись данных в файл последовательного доступа, чтение из файла?
Привести пример использования файлов последовательного доступа.
Как распознать конец файла данных?
ЛИТЕРАТУРА
Березин Б.И., Березин С.Б. Начальный курс С и С++. Москва: ДИАЛОГ-МИФИ, 2010. – 280 с.
Джамса К. Учимся программировать на языке С++. Пер. с англ. – М.: Мир, 1997. – 320 с.
Паппас К. Х., Мюррей У. Х. III Отладка в C++. Руководство для разработчиков Бином, McGraw-Hill Companies, 2009. – 458 с.
Шилдт Г. С++: базовый курс, 3-е издание.: Перевод с англ. – М. : Издательский дом «Вильямс», 2010. – 624 с.
Шилдт Г. Искусство программировать на С++. – СПб.: БХВ-Петербург, 2005. -496 с.
Бусько В. Л., Навроцкий А.А. Основы алгоритмизации и программирования в среде Visual C++ : лаб. практикум по курсу «Основы алгоритмизации и программирования»- Минск: БГУИР, 2009. – 66с.
Содержание
ОПРЕДЕЛЕНИЯ, СВОЙСТВА И ОСНОВНЫЕ СТРУКТУРЫ АЛГОРИТМА |
3 |
Лабораторная работа № 1. Программирование линейных алгоритмов |
5 |
Лабораторная работа № 2. Программирование разветвляющихся алгоритмов |
12 |
Лабораторная работа № 3. Использование циклов |
18 |
Лабораторная работа № 4. Составление программ обработки одномерных массивов |
24 |
Лабораторная работа № 5. Составление программ обработки двумерных массивов |
30 |
Лабораторная работа № 6. Использование пользовательских функций |
39 |
Лабораторная работа № 7. Указатели. Динамическое управление памятью |
44 |
Лабораторная работа № 8. Программирование с использованием строк |
56 |
Лабораторная работа № 9. Работа со структурами |
62 |
Лабораторная работа № 10. Работа с файлами |
69 |
ЛИТЕРАТУРА |
78 |
УЧЕБНОЕ пособие
ПРОГРАММИРОВАНИЕ. ЛАБОРАТОРНЫЙ ПРАКТИКУМ
для студентов направления